{"_id":"micro-kit-atlas","_rev":"350-ef09feefbe06e8483f9bca28884381e3","name":"micro-kit-atlas","dist-tags":{"latest":"9.11.23","alpha":"8.3.1-alpha.2"},"versions":{"3.0.2":{"name":"micro-kit-atlas","version":"3.0.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"src/**/*.ts\"","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register  \"src/__tests__/setup.ts\" --full-trace \"src/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"src/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"dedab2feb23047900307fb490cf4d40425519d60","_id":"micro-kit-atlas@3.0.2","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-AwCz9XhbFTzIwQw1K1lhQfewvToOrv8YN6zpFzlE7Rf3ylonIXO8n5n3zbNluxeKuaDkz9J/UaFtCiNlEN3xtQ==","shasum":"5b1df3c227b8f3b528b09e09eb48d820deeb2f69","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.0.2.tgz","fileCount":107,"unpackedSize":401172,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbTajSCRA9TVsSAnZWagAAvL4P/RmF4sjEOTtRu40WP7Ix\n+ohATUo9lh9og8ACwD0IRtlBTgrRKOWYbP+U54IshI9R3+aGsUzKpDsCs18/\ncRX7F6DYLC62YralsL1I5YtWx3FuMUT6czVK/IEFthTkgFtXwZoWzXwYj5z9\nRPxrnzmqk/dNo5318KrIyQzm2/SScDDRXAA2WQddGfTxTwC3nM9Ahe8oMsYP\nvCxSAICZnrf+ELO4hD6R85he9mH++S78+oXUCi2RuPxE8EWRHrfFy4AUpyUP\nslA78YMlNGYnC+tkawWsjpgz7iS+0TAvXgPXBAL4D2I96YM5Gscz69foIpuh\nkjAsR3FYlJOBIc3gB2L1d5OdBozwu5TXFP3pbG1ggnhxwBI5tSdvOQ5Azy+W\nkBFusC6wE1jLSvlZX4C7y2kzWHm+XYw8ac3TKsQpLU4pfamgxo73l+Dwf2tB\nQ4Na1/a21UHgOCdiswwGvyop9oaDPnVR9V2vFDclsdb0hfClylS1Ir8S+o3s\neFlHZIbaNxgmQrdTOZ+pbkW+9bwoVT2KWAcOEKbSE8bEwnBTAjK9687bP43i\nRYBbHxTXQmQ3GQ60mX3BLq0wss+OkQX/Dtfl4hS5ivBpo2GubYZE2MnX8ZmI\nNJlHC1KRn6VRf8tfEre3V4gMQ/rNzloi7eQAHO6o3K2jEvxzQgZ7T/yzMFFJ\nVp3v\r\n=aHYo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD3EQXk6g/N0l6RxNG9oirJfCqQQIq3lHQ8gDmpmOlH5wIhAK9Mmci1UI7VidMCKmnDXynruRKQavJAwwKARKvqD7EM"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.0.2_1531816145860_0.779899280326811"},"_hasShrinkwrap":false},"3.0.3":{"name":"micro-kit-atlas","version":"3.0.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"src/**/*.ts\"","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register  \"src/__tests__/setup.ts\" --full-trace \"src/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"src/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"99766f241502038e36d566872bd99e1c7255d7a8","_id":"micro-kit-atlas@3.0.3","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-44/2PVMwO978WEsjApMPUOrO1vrebBvNwFsynPEzuHVcz9REhRQgpF/UPInCdK5qfP7IjBZilUsOjUM3pULJKw==","shasum":"1254b26767051c58028b48b8544f3ce495d9a505","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.0.3.tgz","fileCount":107,"unpackedSize":401270,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbTb/tCRA9TVsSAnZWagAA/G8P/0/LuPbzpSs2TntZeHe0\ngcCKhHz0ZBiIz6j6EMghiR+U2X5JnLjlBCvxdmZKuXkjYVAphBwf3h6895HX\nolQXsHsGW34OPVMVJO1T8o4q2rGH94fujQVkw7t2b5ue7eyHbHbB6sVEO53G\nvTxZWUBs+ffu2Injls7+OnokujH8cZwKjqlvqydVk2wRoSBBRBqO+z9N91cT\nj3LCFDfC4MnTqIPoi+V9qJ9JLV4kf5NvqTyCve+wTElWRBqNpQ4ThOJE9Fnh\n4ouPS5u/0BscJ6QJcBgrvim/uRJUBkgiVZweBRp0qXgf1V5uYw3zP9zG1l55\nu2u2m8JOri/9lR8ZRucj+zTQPHsRDOidI5lilAMAXujgEKrjpNOJk5TgWVya\nKCB32rMJIorK4zYcxnjHanGSgE6jsl3tARRN7WKEiqs/jgXaohitWcahjuEW\nqcyTTL8SZUBsNotg6eGn/81TENipM1Mkh4Jppyzvov9pQuOyZX0wftbp+fV5\nRqDIzo02PfIWMB2oQ6Pab2mfFI464kJgjscuAGt6LgxoPu9yjSqJlBjzGHMk\n5V51LvSe36V/vgmad6VdjqITdAE/ZaivegQ9U6mXHXOW00bCHbuCsjpz1GmJ\nyoByrGCRLt4guWZ9e7MASZ6F5vjo2UWIHFFr0LSNIOFqu0XgoRO8UjF52hK+\nRj+2\r\n=PT3z\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDBoXhKuEfFRNk9THNwiJ6coRuGeGqOMeJM+pNqbXLJ7QIhANbK8RIxaZz9DXuM7WLz64RSluezfDToqL3NFdGsnPUF"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.0.3_1531822061651_0.945451238697816"},"_hasShrinkwrap":false},"3.0.4":{"name":"micro-kit-atlas","version":"3.0.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"src/**/*.ts\"","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register  \"src/__tests__/setup.ts\" --full-trace \"src/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"src/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"f38acc1e8b06f946f4a795667fd2ca96a79149f1","_id":"micro-kit-atlas@3.0.4","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-SFP0y3hHVzqlQz+qbE/634J/hmx+4GYn8XRiTYJByw5j8ySSD9W1UUzidm9W/vMDKocOZNHv5hw8Bzunht+gvA==","shasum":"72eb9a1e1f97e86d7a368261e3d9a4ddd36046ad","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.0.4.tgz","fileCount":107,"unpackedSize":401373,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbTeOuCRA9TVsSAnZWagAASr0P/04P/llNtDG1HSw7dPhS\nEOs9wY8bO5o8TfEf/zHWseRTXCALicMEdHiBlOzs+0KiJJk/ten4sUoKeFGi\nX0xPoYtR0VQBbs0woDlL0OlVtwqakKkjaabtPs5b+CXz87Gsq//GPXdKat2k\njXN2xQ5Du0cPuMAF5Bu0zhHAIzZM+GZSt/eEkOhEXIZyJWoG5LuF3/NI6Wsd\nGk2XZ2buhUL//xE02mpFeIPIy3XXyCKvLabjluIFa9gQQ4mKIzYiRmxA7Wl1\nIhzB/RhSiborQKSYxWzKSFB9r6iNlE8Ld9pfCIlAN06katTjMbl7rertIWWo\nUqKQYpv7FQLM2jYBi4NWQnxIRFfR5gIHrmw1AWPt64OT7zBQzRYYfQqm05pL\nmAPpcdCiPwVpiY7lJtN4+xYaaPRjB1nY4x84pSdZ5UJbS/tgEGszvR8YoBpK\nLkf5uYMs3/5Q4LWZvrkgJ0m4ks4BD45F2Low7AVtlav0XqgEDcGU0GG7WsPJ\npnd0zg/emGuB6Q6pRbBLVZ5QIpa6u855ZSM0/WLJ0Doh4+9zdJ6Zh8jr95k1\nIPZG3dv0AlNJp7fvR3XXD54RFU5YGphMwTijDqzIXv9Z+VBqcYfjXyoae1+6\nRz4UTwzLDpl4VNPneaTvExjploU+q7XRAXY/tO/a/XCkqrgUMBla3lhengbn\n6Le5\r\n=Lb/D\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGnDhYpcQ038liVS0vLbFOlzt8eLjeEppL/qnWylaWnbAiEA65q5m4yQLuPS5HWiRhcvqhLf3g/2max6HhxiVqgCuX4="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.0.4_1531831214493_0.19031413414359166"},"_hasShrinkwrap":false},"3.0.5":{"name":"micro-kit-atlas","version":"3.0.5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"src/**/*.ts\"","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register  \"src/__tests__/setup.ts\" --full-trace \"src/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"src/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"6f58dafed1c29cf0b708bb0041aacbd04852c7f9","_id":"micro-kit-atlas@3.0.5","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-ZYpuHwxex6nYiApzR45zbTirKDlqZgnmO18VIvudd10U/scmG99pHKTD6zS4x3QsM476mnujZyQDMwISSq19Pg==","shasum":"47c9b0440675418504f5e0b6aa3b865a9623380f","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.0.5.tgz","fileCount":107,"unpackedSize":401401,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbThKkCRA9TVsSAnZWagAAFkQP+wdsvjYLVUeTSsULJQxI\nzHOnfi5sfrb/jbtBPshWqmqHFMGTQaw/8WuIMfsabVEdzYz5g2E5cc60Q4Uy\n937Mgslu2Tg5aFPwWUSUIbdVg+DN61CnoAw3IUkmsALKCvpJmiZb7/KNh3gj\nBPppf9JJWN+j1r6FZWSxE9eaDI9rno05JrNE9ZQAmm+oAVBc9g8jHhmp4fnQ\nrR5bt0urQBBeYj1qI4SjahIkJXn2pPHMwrm35vRheNLf5jC4dtCNJYfH0YCu\n/awh9eC2YnNI5gNnCEC4XWQrlZJ8+HChEPRD6zKlEDmZ4LIrsOltB0KAPOny\nG4bNCFz64iJq4wE57dUUiINwkQkFEz4wYbThmbzgbYgSnD7WWr5Pwx8KZCmS\nihgHiNkiNDLV8KWL8esP3KmJB4tiFQXnhl++Cmx7WKQBOnU4OB736uDZx7BI\n4sNITIf0DXP7K8sA7EOkSquscIPWLVLZ7d8aL5iIjIQFMO2o25M1Az7bT3MQ\nGHJmkicKWgkb1gqaRsDUvaQKZyxDQd+75qa4W76gHXo8xjPF9UT6OlgBWhyV\n2ZusAZYcZAqKfidfNh/qong9h64fjRWvlwvEqExxa9l1r6ceQopni3qQsyD5\nspSbZk3FT5q21etDmosgj3dKuhND/GJghL6BcPXPfPbuJ8JbRZ24JR1547i2\ndiYh\r\n=DLQK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCI3yuqEJ+Pbx2ybgSvXZ76HTfxHzU6j/4QlFxiH3FU1QIgOdTi40lzxgGXeW3PXL2fUy6NkaDgvr+D6DLdozIEAZc="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.0.5_1531843235754_0.8260447797783388"},"_hasShrinkwrap":false},"3.0.6":{"name":"micro-kit-atlas","version":"3.0.6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"src/**/*.ts\"","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register  \"src/__tests__/setup.ts\" --full-trace \"src/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"src/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"3e5b81ce86751b89b966decf10d710482fa72631","_id":"micro-kit-atlas@3.0.6","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-w8GYjQKkxQ0TFu8HC1cGgrKiCYH2FJIDidgiwFEEbDzxJu6V7dtpofW1K0G2qWmJlz8Ke7NTlceOOFtbJdYuIg==","shasum":"6bd65593f4b04caf06163ee14a33c23bc3c7db6a","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.0.6.tgz","fileCount":120,"unpackedSize":423168,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbepPeCRA9TVsSAnZWagAAmJoP+weMv2f88FOjf5sAs+mF\nXyh/y2AAeUH3QG4P2NULjk34rXkf9T0GUeWpTJCpwMkpTDo515l+1PJTyLC4\n1j69hCRA1OKM76j/O3TxutvmCIK4XJTJI/Az62z7Uj8wZ+Imb5Nm2GJUHzcl\nQDJuone5LUhla6givKXa6+XXVm7dCSm9bsfZR02iPLGYL0oz0+bGYbntJQ/h\ngS5MPtmOP/O+OHISXQZyLgRQvqSgXA4HKBl73NAriHGOFwzNXwHMggaicyxX\n1F/H/1ZZ5U/vHOA0MCWpyFQtr/19ny3mJZg7oL0hlV4/IXdsCkqdMLhjm/PS\n3834INoxIE55YPAeTyT+QQ3iDP+kwcXt4pOZuOpfY+EblhP1aEqqwu9VhQ/P\nDsAkZeAQGQlZA7ywuYZjcI9emg4uNwH5Ht5wX53xVuOzpYdWsSAH8BFO8z6d\nw8Y7c7t1fnHGzJ8SKaaiFRp1qi4WrlVg0gub06OMjLba9apdQXuusTA6zldM\nVKdeuNNUHNipZDpV7uuzOxnns0oupJF4146rp/HMA4WWWaYFSXk2eLH9S048\ni0IskFmFsHewrnofHvftsBcDOtZeh71iwgRKldNCLne/wbamnkhC6GTxrQnJ\ndyxwSOU2jLK7zVNRs40gxz/LKLZFes51c93Az4x/m3HWuPJH40wazMifZm/h\nS8oK\r\n=LI5e\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD9FGrxIvU+r44D1nzSkUtURDSc/9otsekBLrJqM5rVKgIhAMknYxBVhA0/P0skunjsqSDzGzFF1xqGSvpdw4raIY4g"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.0.6_1534759902434_0.3499617615178583"},"_hasShrinkwrap":false},"3.0.7":{"name":"micro-kit-atlas","version":"3.0.7","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"0899fcd3e91f03ec1ecc6afe4a371f0730e00b12","_id":"micro-kit-atlas@3.0.7","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-D0DevidThFunYur8ZSOKPagoNdKS2R9d+y1h02h/DLqARX29WWqoDCa6jCGBf92/LBU/i5ZfGnrHGutm4p2bPQ==","shasum":"33548531e8722526c7c0a95b34f6f2e8a585dc65","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.0.7.tgz","fileCount":99,"unpackedSize":364421,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbjRM6CRA9TVsSAnZWagAAIIUP/1fCBF8quRVa2oilxRJ2\nBi+xMS10DFNUn7LXTTK2is4TBIxZmUcPtSSViKocu86LnUkvQq5EQx4f8cwP\n0BbUtWx/h8lw+946bxxF1WIfpQnk0t8cLFILt4DtlGlA8ZuqotX/UjuH9rrq\nTW05gP+e9zM5NoC8pH+sN+BC8csAqUMmLa9rXY0fAa4obzcTLLvdhkfZRWWG\nO3KmYitHuqB1NZzpI6rVMUmcdY7Fx+ZhKVFq08Yl8r8n5ZMVHBhVEDFVuSQP\nY5J8aY27tILsYWXRYZdejySu5nUlMvykdim4RcUyEIZHFof3bwEkq1tzlz2W\nDoAc3XxPIwYEx8BUKtICbXQELu0QC75NhOKmFFEQ6W/6mH36rEX9Zx20/V/a\nAt8r65aP+UdrT33sAswA/oQ7o9fMNAgdpKHZkf4pOfklkztfiYEPYU0kbzFC\nSYqsx+9OTkRPe0rzHYB1fzSuWL3R+nN7njZMkpDWlGt1/XQHbfVlXeeP1vKG\nUWoGBEnan45FeVRDboEoO2nIqtIZM5ijvnJn3FRj3dQKv/NQ+GcGkHvBRDH+\nGy6fr6kwUereQuffCEP1OttNrh3KeVXBEMci3OBMfdRUsAo0i0DGst4nQxYe\n8jzo92PZNBQPIoopNvgKxNRFY7m1GEw3/l4sARbL4WP4xrVqBjaz4E262t6z\npjKf\r\n=QgAs\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDEwYVPtrathwUlVpRKJL2r1mVIQhwp3WGCJPfnJMgamwIhAOVkuqXpQTmb+xNJufR8BcuoFubaoGEFmT20FK6V+SWO"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.0.7_1535972153477_0.31669961756327036"},"_hasShrinkwrap":false},"3.0.8":{"name":"micro-kit-atlas","version":"3.0.8","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"7d73ccc0852c04bb36d27b1d09ee475d8b9e0c4b","_id":"micro-kit-atlas@3.0.8","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-gRicA/QWARAaLaNOG1Y5VsKFy0OuZJUTRKy1w24rVsj1ZqTK9hWPDU7SW4jptuclFHETmh1CCaH6OaESU19OYg==","shasum":"c994388faaedb9a3e71d1a2b8c1f6b4e4d615f0b","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.0.8.tgz","fileCount":99,"unpackedSize":364445,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbj38cCRA9TVsSAnZWagAARR4P/1sODWxzNJT7b/AhGkww\nymq8Ro0Tn1wE4pMH+m7L6wbNiqo8NLBLtAMCpua8Uirr6PQnudIQ7+GplAA1\nenTDOiHQYLUxgAFjZST/EUZPjTSkuqBOmhgGusLeJukIi7KJdPl+ryIaJ8x0\nVZ1IaALNoDgwS39CIFVumFh0oBXzhbczxsdYv4RStc/hrtIb+fuS0gcqh3ng\nAUDuZEYCbMx9HlFY4ebH0FCpvuw67rhNPdUJO8sKorr6vIicEchKPy6e/7L9\n3mm7eoivRqJEY79n0bOdO8kPV84nLg9ifidS3Pcrm3CtELpyHsPjLH92x4Y2\nX4F0a2d/FilWJmaOHz5feHZuhw9TJjfw8LN2VJje9Wb6LhfX4gVES9yE8a6J\nAsEPzn437gJnrvIZXjCvBX1gjQzNDHcQTGpcV/buYmhxeu3IYCf2CllKDGtv\nkAN06Ua5CdqniYul2t2yldaAmqeO23NAR0nbQpasS1ffdOjD2jfs4iMZQDUj\n7Viqm4geOJkxbJzIIvni0oWKAKIKF6tNgxxa3UuSToSm6pg+DnV3o4+jU8FU\nT2r4L39/3qlKPkcO9OSBaEB3T/hZnH6j/8h35rXbSoSOQxMxza5m1HAI4dR2\n8hON+zkyVXRo7/rL5R/jYJT/xqHBpD/E8+8BkL6UJqsnXmcziT+eQKzYp7Ca\n6njU\r\n=obiJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCMKWrk06cXujvv0tKv8Y5xG4pS4iq/101nXML1JuHRhQIgRmZF95ROXgW4VZ6YAi0470KhGMCgNq9dlokXx3w2ljg="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.0.8_1536130843774_0.7181255807084015"},"_hasShrinkwrap":false},"3.0.9":{"name":"micro-kit-atlas","version":"3.0.9","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"41b263560e298fc00623bcba2edde6fcfa3a1e86","_id":"micro-kit-atlas@3.0.9","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-iifC8ixQX94NRKiK3mI8na2xz5RvtsLS33CJF27lgL1xbm4R6uco7Vx6Gs9PjbNS0iFKZMKY+GlI5XvZAF9cIQ==","shasum":"03b4c8d1ae58b63067a9489de053a22dd4472b20","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.0.9.tgz","fileCount":102,"unpackedSize":431861,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbl2YGCRA9TVsSAnZWagAA8RsP/35J0fFXUEWaZ3IJR+qK\naSvPUcgqy8AC69Lf3QZGKODRb1GTldq9dr7CD/NJrAp2pUbiroRiRrd6MB4H\n9B9m43z3aP3aa7R/xkQldJRnlT53QWPgb7tK6E/4z3dk27FCVFnP/tDSAyBX\nJIQNziiPXp3jKMFoWRz61XmDxp1z+lJcpg502P4aszx2aM3Stk+v9ythLwfE\n8aqIVpI9WR0h76J7hWXolLCMvBzB47G8XiPg9gEttjl31yros0vsKIuY+DNR\nGvgXoXqFSVHK7AHmheaawjTB4QvnuZYTH3a3Rnjij2aAHFEKiShf/RYxV36i\nBaQ6CePET4EJVygu5j/NkGVb3GHFHBpXUC9/dkYhARP1Mg4ZHm3rGEAd7vRD\n5OZUhBU2H2OGE4RRP6F9c/CdLxPzgdAdDLP6D9k0+DrQTaE3i3EjSKxK8ejb\nUx+o03JW530DdGfpdak/17NwKMtBTw1xmLBSK9YNxYWqWPYDVUU6apeevI4C\nObVWBiKYZHPLuv9IhgEjWwwcxT1QB1rq5PqkpYR6x0EFr0Iov3wewRqw7Gjt\nBIufQ2Hz4mUDuQ42fYjGl8XpOxJb9t9eNXRT2GdZ/9MjyiAjChkdYXMjHypa\nTBWNS5ZlnbwB/vdjVYgaQZpcJonbR37k501w/h62EOUxP6ftmBRneS4n3DXs\n0mU1\r\n=qGXm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGHv7tgxHZDv4AwV1uIT0Y42uj7RNL7oGs7c+0T5QGd9AiEA3L7PiMiVXf8pMsedYJtihEcrAIr/U9VEXGXDsbxShDU="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.0.9_1536648710179_0.8713362107432616"},"_hasShrinkwrap":false},"3.1.0":{"name":"micro-kit-atlas","version":"3.1.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"2a3ceb54c7d93be0f4d7624c6b2c6d20caa63c73","_id":"micro-kit-atlas@3.1.0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-DokG4but68Cwy1odpapPJCJu2b4G+bXI6nYN0kLV/WTBQocouule2GWK8FXsHtzM/F5aDoBzS7P8Tz/zxhUGFg==","shasum":"372e72b5b4bf182cefe773cc1137b9e04ca31a1a","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.1.0.tgz","fileCount":102,"unpackedSize":432027,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbmQDlCRA9TVsSAnZWagAAGggP/3Kr3+28RWka2X+RORUb\nW1zbAemkBce0Xo5INaVHd89x1rWVERB4jE3DI5rFJ4ELrKS0ip9D4LXVztWn\nqYsa+kpz0DSktAfpriaT+BkYMYbXS0O2X113sTy/8+q3WE7ymmUDGS3BhIQp\naCtBRBXKIry710ATCcPXDeozvaXPfWe7ZZVl7LQ5b4AtJBMvwOatTglMz6zw\nogkH6ShbXokM6dON2cyHLEzwp6EvXJLcbCOfMzGVCK7hr3JklDVrxCuumSUF\nK+I9w5Y+c8jZ5UNk1pYy5wTp87EMAY1kLbvFNE4H7x1+j6rJLvY0nLayYVCK\nl1V9npGoImfIPbcVK2OTreiEVGvIi9gYsUdBYoVub9uLVWHQvQ0a/DvWtCnM\n64rK9ATWeLLsIZKSZBa3+pkn3NQW5vdGFRpxAQrLJ1fUXMtAXXxzZJEesPDp\nLSCoh5RLQIzc6QIpWNCUeQtND47fx4AsMW1IKLit6BseUoYr7SEBg/OIeGLP\ngh92bUKOI+/tkazB/khIo41XXtk5Z4c92SCytUiajtNQ05iebqG30jRV+oqb\nsdN9hsPZtkYuDvP2O9YxDAq40MuirYQVAgxXzz2hSGpu5ApMgljwDTfkt34r\nn0ZWpOF4EHgaBI9D1vX0cI/cINtT/lEg+d2gC4yqeDyQ0JRq7RyinoMfSFtn\nuVRv\r\n=LVdj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE9EndF0CepDfCH/9hoQ1wp1tWmZy+6XrYW/a6bTE4m5AiEA5SEfGV2WM0qvhNCEQwJwWDnLTvgnCy//AOdRGW5Mqdw="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.1.0_1536753893122_0.896016302249818"},"_hasShrinkwrap":false},"3.1.1":{"name":"micro-kit-atlas","version":"3.1.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"b8edd49f2691dfc5d73e7157906de7819b5a7da3","_id":"micro-kit-atlas@3.1.1","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-SpQ6fdAx4UurS23rTHeFQCcm0NjDSg/N0Ut2K1dHbxYvPp791KQLZ1CE2/9DnmtQeocCdYG/QXcelrNeU/vqWA==","shasum":"22a8237d7cfb587a606019a9d32a420f219cf33c","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.1.1.tgz","fileCount":102,"unpackedSize":437310,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbm6OjCRA9TVsSAnZWagAA6W0P/0YUkFUuZLPEta49G8nr\noW2J+xW9Rcw5dRkB0PT+yGZgZz9SDHHj3qjYbwUcXH0kDP1UqaWgNEGnWmX9\n+HXWsrgAOSCtkmykBCmmsmy8uV0LSGZV+N3A0u8NvFsTxKqswVuBbbkzoNTN\nR5Yxf1lTe5SfgkFy6t86GwtHRGsytADr0vV90bOoWWPRcxBgCgst1mnqc2uz\n4f5EJU1abBDpMVe2iKVk5/SASvkMx6a9w1AR/M9SWXjQkOoTktv8sMZXiTUA\nEJ/m/Mbysh5h8LcRpgyn14KRW+cr/sVZsV+O9p0G/8wLuPlCN5FK4fkiI5xT\nfXAfO4TQGxaT4pL7qzf/G3TLdSlaKFDhStAcopmtERZQPvfiJh7NWBn2tTj1\n6wO0AycyOz+mSxQfg65zSipAM9QTk8dgyrThhofNUiESB9EH0OVU0KNwmvF+\nR6o5zsu3YS7ACvbgjGGJ3WB5ZWdl2p+QFqAOIg0plBP3mLjMWyShnfoMK30e\n84buohTM988milgi774GSn6H8KcDw8eZsSXGNXE6F02G6DUuMswGe6Vnod2d\nPTdf+5QCDXQlsCfWX+jhpPn8ZBRmplJp8zdtpRM3kXwaQq6d87BA4wxX1C2x\nvUWTZiywgCGvkLTOKkFduRIHe9CVTbKx3fv5g6aqA8TTvw9+ej5uCIECksnR\nYj17\r\n=cYa4\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHvDMsr3kXtItv5q2L/bmTbKwj3uqrMW2e60K4Bj4iHLAiAmZRHwvfY1X5ncl+rZKUtlyn6DE1XjcxPU8jMOfPwulg=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.1.1_1536926626432_0.8216597176912803"},"_hasShrinkwrap":false},"3.1.2":{"name":"micro-kit-atlas","version":"3.1.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"035c8578158263c616ee2359bd46a2b857426c31","_id":"micro-kit-atlas@3.1.2","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-gowZPovsKqUgzqkwKtrRHQmL+Xghb80y1gdDFeoMNM1IfdZKeIq8SZ9IBUWMEt8d2tJhL+/Zzlzw8n+sTsdzQg==","shasum":"5af3d29c44f94d93a3c5af8a924392bae0fb0002","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.1.2.tgz","fileCount":102,"unpackedSize":442968,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbtILNCRA9TVsSAnZWagAApk0P/0Bw7/5ZTVKwuGJ5G/ch\neojXHrijqPdoQRqgdvwST9DpnwafokL86DSorXfQSFsIB9rjtzYGtogemrvF\nze5uVziWLkorxvMcdVvhVpVEICtW5u1xyivU0qF9BJwwOYNllor+/BAYB9G8\nWFe0lei+LjA0phJH2kor45VzHs5WLjxOY6zMhXO1HJY3VfxwB0YMJ8fnshtA\n+0BeLxKET3XWMTnWXB+sEqocK9AFEpQ9nY/Rgg+u4dR3fR89var0L/GEleL2\naE8GwzgqOOio1hdTGJWQ0NHrJt4zXXD4rGXNTd3iG0EQrrDlfKMHcFQswGH3\nobEixGLYJhlutKdnvg/lq4IZR0Kzc1rrCK7nrZ28DfNqk21MUGwzvatwFk3u\nbo+IbpS7gGcQG9wk0b5P/OfOOAbUaHiPG5HyrGaZIv+ZamJVQoW/+qi2EkRM\nxovLmbHtlmL0ovcziLd/53GKnFxwfj+l5zzlbOtuDVO4e8qSULBKs1dCPVoe\nBh+4qAa3BGBD3pagnmij2qGLBFOtlebuy7m82l80OVJzrjhKbSzJLsQ3zlsv\nrqdmyFKctSiMG05CXP5Kl7qcrBaTa5zjs+LES/Ftb1Gyv2eaKyrlxgw4pLTg\n1Co6eEZD309/KVZm4UtRvAh6RitXLZjmZWUsnfbyQjTCxq5sXgeR+b9fYsQt\nhWGs\r\n=82Lm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHosPpMxo/1Dv94buk5OJa+wiY/Y+en7ie/VTPY4MNH8AiAiuD+w+P8sXQAocd6BiFw56ZfmDmqEBNXnHRUSxUnREg=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.1.2_1538556621437_0.013581651857021537"},"_hasShrinkwrap":false},"3.1.3":{"name":"micro-kit-atlas","version":"3.1.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"34606dd7c2eec49776e96e97515328abe9206730","_id":"micro-kit-atlas@3.1.3","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-c1ptmkQC6OcBHOUuodf5i/2IDJ+4wkoqLKQVlTxiEgk4BwUV71jEt8g0ALZm9bmdCx+DZmiYI6DxllcC6esjbg==","shasum":"fc698d5a047fcde03d05308253c6183c7126414d","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.1.3.tgz","fileCount":102,"unpackedSize":443394,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbtJ45CRA9TVsSAnZWagAAFj0QAKTxAXnjntlfM/KRqUV7\nTwGUP+9RmejCXdLw8tlUc9hLdDQZeg5nnHmngrtFUJXJaE8PwZ94VCDPqNj5\nfALk+1LjoD8pJNBzP1fdwvyl5qp7dvQcZcVHbz2fPTZgwP0cU/FO/4pXYkJ2\n8M3uZ0RCDLWOWVCTmlKmmirwjDRMHU4+EQ+jJrmqCRSZELB5gCMUsPiFHGFa\njBrnaXkxRmsN3udYRKmFpieJpd4INt89wymjlwZE7DfVrxNqo19L53xapZJZ\nPxwrIHeezf+vGhb6Z1UodB7P/b5n2Nab1Dxy7R9P+iJv1TfxNe7QpKatRR6l\n54HpfZn8T+dqBHPPYA6gIPtLysgLGAaX40lJh7GEghCfLZrjJ66vCXXddC0C\ngTAqgLjwkEGYSTVROQgVmp42sobckc0hW/crOCneckHWXMaLRjfURPcuu3i/\n4bWyRUHUB2/ygoKGOOBbrImFuzElt2/quaPsTYonBFx9r8jFn0coHh//t9Dr\n8GW7Q7//08YyNDc3Jh8NbAnohQUe1DBZ30NIjhXD60nia15FXelAr7fsGszi\njdqAVLI6JDnArm5FnR/jUZl13YGjnCZyi6JIUas6ocgukJPZ7sW7IgMKx03n\nzXFAiEIWxRGQZSguX89xQzMbIwcuBQGPsYwSA87zEnlJQlsdIvnGI7LCpbCW\nU5F5\r\n=K9U/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDNRMzv7ycV/+GI6ev9qx7ksPchUPoBMmHQii5j0hMKpAiEA6255mbUlleeKXoX7GT+LVYSvDG5akzlUFeGXH9OYJ/s="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.1.3_1538563640483_0.7091729155768591"},"_hasShrinkwrap":false},"3.1.5":{"name":"micro-kit-atlas","version":"3.1.5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"063f4f73da93eb9d196e323f510523980685c203","_id":"micro-kit-atlas@3.1.5","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-xpnjUiszboynfdhr0U3sPQizqbDWa7R4F1amNpKUnaY1EmgQ8TlUPvMwCiUpg0Gsl/nrjeoxoB1yFibXLbqhSw==","shasum":"2a6c933004ac318af5973b9453d344bfe873330c","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.1.5.tgz","fileCount":102,"unpackedSize":442831,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbt3kaCRA9TVsSAnZWagAAogEP/2meEV0BZ/QO5KYicW3E\nA8IuKW1GcXzlyygN6Ll85QwSJniw2cLqSibAbGG9OtIHPiU+d4gcb29RW0Bm\n3NkVwzySg9/x3J17xNwHObioNGSwJy1G6PMgH5owGYMM0queI3iTdx5NAEWa\nEQWOxczdROqdOjXhvqTbJX9scxeOv02jLBD8sYufvJ0UFBgRPzEtOMzs8KgE\nMP00AX0XfUiK1O3LZng86TBuGkm7gpFPFpKP/tFWQrv0mHq9v37QtrnWbg2J\n1OTPk64QWTlh77voO+ud69LLsE530qvUQBjpilKqmV2bJxXFqL6U1mTi1iFq\naFnpqBgC9vDs44MllTyzCU9iAkhCHFzh+mkd2jlfdgsEK5fWF3ZuKfsO73ra\n6j6r2E0ITvWqEdUQXUjoNiztlftjZziJjD796Lm0x4mtaYf7VUfZS/N9gCUw\nlQjozhEhRqC0ZvyAxBENuwkucBtC6Hg9fqfIEAFLXA/nckRHlHtidltj4nQ6\nYp0yehr2z45Z4WddUSz8GjEO0Rgggq44Tf1ofAsK2u2eWISDagHyaoLeDDKF\n9DdPq+ATbe5Es90opNknbTgT2Mrd3/vuhWRg8z2ELtkqQskA0Qee9oDp26DM\nxQup0qB9FcLEcQwEWYAFiBvFVEOdes/21OO3ltv/EjuJho7bGwKJC37DuJSy\n6u2j\r\n=Qlci\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD3/kTdnbyu6Oym4MnMTvP2wORCNl4t7xoAoamCXsyU5wIgWvwXJeetuB6qlCy+lNs7g43rDsYnTP7YFDaFdtD8a44="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.1.5_1538750745116_0.4374956811792723"},"_hasShrinkwrap":false},"3.2.0":{"name":"micro-kit-atlas","version":"3.2.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"a0dc0b61762bcdf03800470aaa57475526e6fdf4","_id":"micro-kit-atlas@3.2.0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-Pcw7w7gygzqdqGrvuKaOtjedNB0xFWJ+rThs5paB3R+4eR2paXrMgF0JdYdoBcEF3X6WEEgYY+K3yNG2tLfQ8w==","shasum":"69de2a746b2326204e0e7c486871614c3ca1d7ef","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.2.0.tgz","fileCount":102,"unpackedSize":443268,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbviBRCRA9TVsSAnZWagAA6xgP/2M+PvyeWvD9c1z0FCtP\njGdC0yAyyNO0U6p/NR9PaXwuf3HbFFu3Cxxn6mMD1yccwpUi+Phftj7dORLA\nEKXiHF+vCkpNSmhhfgYfSBQ999yGpwpaM5jOLpylQhNubBIdREVgIMxu3Aub\n3Ivhs8UNPxFAy3YpXHxC1aiqBKMOsTWCdyttwXcDdBNgzVgKpYEyFV9IUO0h\n4qYwgQOLGrLbjTiC5NPoQXcd7qtWv04hzIhzZvWSgChofkfIrEAxr1T+MRkY\naI5Kbi33Ejfwf/UDoQiJeRkP+CW4mA/TSkZL9aNcpxcsTosUUoCZ02u8gh+l\n7t2PKrIZRMlxnlltgehDBay9Cw18y+5IGzeuPACNgeG3DBswyK5IxoWdAiIl\nUXX4bA7/3ZAhiA7Ozqmpw2Ze4klmDRWLBVEnKxK1SQ6VkKpyNe/T2+jP131W\nYjWEUleEAHv+ikPIeKulGAba+em5Gf0SmGOPOstdSxOlArxSdLrVMmscxxkR\n+2hPeTPAluVXIJoSl8tRm2TwjN8oi1LRirMnAPiIbPWSgruLE3aI8XMb5iDM\nDO5P5vw3W3wYRvzw7KXdkswELje0c9tUD6/OUKZ2k0QQLvqMAeyPwgA1sGIN\n1skd5TYBhRSq8v7vtttZDKM499ZTzbFRdGb+EhXdkgd8pYqoK8c+QHGYwq5m\nPGq3\r\n=RXQo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGZiwajrlFs8ZiKdCEB2mDu7cex1A5+3nmKU0hY9I7I8AiBpFJ34dGBMRjNgRDpmrctLCOLdMeHq6aYxNjsKf4PoTA=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.2.0_1539186768356_0.392941840595707"},"_hasShrinkwrap":false},"3.2.1":{"name":"micro-kit-atlas","version":"3.2.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"a0dc0b61762bcdf03800470aaa57475526e6fdf4","_id":"micro-kit-atlas@3.2.1","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-YQZUVCApsfgF97uj0Fj7BmzyGjqEwHXUvoU7l5J+AHYWyQJlwunR3XluezA6NmP75kiaR8tkw8n1Dbhzn0ftKw==","shasum":"81ffb21d43878901de22f3463869927bd8f6769c","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.2.1.tgz","fileCount":102,"unpackedSize":443268,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbvxmCCRA9TVsSAnZWagAAdTUQAJzS4SQVeJ36R3Pn45KE\nO8DxSpslo0FwjOW6PcJlkpLDXHMn0ABFIuH4hra6Hm4r3/Fp3GzJdpnSwVTI\nRHNQD/uYRLQ1fFUNaLBUDc1poBPA9sRUM2CU1D2DH1PgAzPKQZBImgYM2fxg\nhqbzy25N2aLdpuwyG2pY3GADUNxCCiej31dFM4Rkzvc5qrLB3SrN5yNO2Tqz\n9XIqYHcapvTe9GLNSrK08Jlr/kPQjomibzh7/gpDCz/AFKasn8Jq8nJ29NqN\nD2ke7xlG5qVZuO5SpjEiAOHeppDrAJD4ZMAP3Zz7GzH3M4y/fhgq6Bw3QbUT\naRBIgKarBPtxf534jT5SP7K5a9QsAeVOJwlLO2bkAPZCRTNVaWAF32FbidhI\nh2MBtxnpQ5C70VK2D1ejrkKwYpHLeUZhcYCTXTYSKcMfIi6uqCg//jz9SI8d\nKOSInKHw2eiAbvnMoYrAXG6U/mi88NpHgIOQ/hb8H5NizB/AIOTzs/caKgn1\n6gA11sri7j5eXaJdTMqkbDn2vdbH4j8g8EJkzqKODWirsfpA222J9OKl/4CM\njveZCFaFN7+bUnBHSdSXiUmMoRvmEupzMxMB9PLJGRmsOomJZbrlaz7rE19M\nCzC8JHGpAfmwRmAK9xuspBwAxGbdl8voZ5c03oWSgZVXfwzZNne+qNN9bjpr\nZH2Q\r\n=mko3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCmU3umk6mRpU6FG6Nf4cKhbTB37g3GIAPrpKXBO1SbpQIgcylT/9Lz6FcQjH2sm2AGxhm7d6Iwtd1ereYhUxvn/V4="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.2.1_1539250561315_0.9191727311639422"},"_hasShrinkwrap":false},"3.2.2":{"name":"micro-kit-atlas","version":"3.2.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"fef05945407a32056915c82117c202d000f38e95","_id":"micro-kit-atlas@3.2.2","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-wvwWnYAzHnZNEh2sjDNN+K2UrgdMe+6/TEM36vT13jS5Oaur57ji08LEG6NGFcqtt8ud0gYu7yPD7Ejrn3HZ6Q==","shasum":"8e328cdc6c4a0c88903344e6b8c18771974e79e3","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.2.2.tgz","fileCount":102,"unpackedSize":444094,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbvxxACRA9TVsSAnZWagAAw0YP/3rtw1jcWETHQj3KoYC7\nW4Mz7maXe7dyOmPoPB50/zUGDNZYcjGgxGEcCPS2KXQ5GNdJliFQchWTGvQV\nz9DpCF8KHsQHmmdrHJfSipvlRorfLeim62NWpBZm7iWoRKjiC53vmamoo4gC\nhz3XwEXfc71WH0N4lhuBtLutWS1SGksAyFOznTxGHfnF2W2kzsudgcrdgMJq\noM0OeENau806BBHbUpbCL5wOUnljueomCDXIc7rs3VtbOBvNlbIHuXY3KNYL\nKkX9Mf2kv0a35Wv/RBVsuRi9GvEhojlCfgTqlM60UUIKoSNaLgMNLkMRAy++\no36iZDTLdt3nMkP7Aoe6V0RxsVKBBEGCI7VmbcyqKDPaoS99ZIQTVgAXNtwI\nbIuMlCPY6kFqgDvWbxZ2fuJQomZQASsP8lK5eaIpumme9u9J0KI8/YsX9oGF\nqIk/EDwJlFFArSONy0hQWQn5r38n8trCxuQigraNxv55wWaQVveZrk+9h4Qt\nUVzIAwEVNz4WE1qwzKTR1YrqWYMfo7xPXuGrZw+wH7xW8KaboroKMMQcYGiP\nqgGlNocHdyDQZdxCeRsgFtbFOHaMnRZnUG+lCIEPGICJyYlfOTU877OSX4Or\neAgeW900vhwsZkdT/ga4gIADgtqquZFbwE6nWAZ8EtDjbp9A9wcNcB3y+89h\nbGYo\r\n=Vsgc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCleW4D23xGt3WRfKMGxFAduN3NGv+AxGa9ac9ctzCcAgIhALRqgE2fZ1Izi5ZbEIlnvADmKJhIOSiw5EOJjVDc1eaL"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.2.2_1539251264040_0.9395476391632969"},"_hasShrinkwrap":false},"4.0.0":{"name":"micro-kit-atlas","version":"4.0.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"584d6cedcd4a57b11c9cb88052b0b1d638567bcc","_id":"micro-kit-atlas@4.0.0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-LaeD0y4WoenuVJ5ybiDPZThmRJykMoXh8MGlUq9DVY3T+keOjanwVgNZ9UuasfzCbGWnKMuXE3WZ3l7FvLlkbg==","shasum":"2c0c361cb22a8787b756e8834f2c3ac356e9d496","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-4.0.0.tgz","fileCount":102,"unpackedSize":447261,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbv4FZCRA9TVsSAnZWagAA/WAP/iF815KF4xzXCNTMT1q1\nB4MBSX19qbArwDHeyvGCbMpnqs3H2j5WBVODtFYv3BQ81d6gSWOJUQEReD6n\nvJyFFFuaZ0+acfml+ifqoPw3fPza118tAa8TBs3swD+9Kr+912lAa/W3oILP\nBuEgc82UsKszft0FWX0uRQIgs7yE3qM0JM1jg3sRNnST4uaB1d49O6ATDxU0\n+ODhN2rg+mPnRICK7EuvKaErEqCsk/a4zTuIdhqg98ykk5dm5rQCnmD7VnSD\nmBYVpk7WoY57J7kPwKkQlfv8/Neq+P0PZ7nNCyH9CVkLjd69QxKXAjF7JpC4\nU2380ZGytV0FtwffgeTSz2cg9zfKh9DRQkYTdUvEqgbRcTowG+OfgmduXHVM\nOWCGhmPr1GePgrU9+9S1uZugCvcVtptzrjQ4wdn3PbKx7ciYobJm5vnE9yOb\n4f3uBw1Yj4r+NYdltoyG3IGBpiKDpRwDUT9d/4qRXMYf/xRBJxmad6Rq0Jif\nljkckOi5XT3PGxyJFCqGQumHQvF3lrFTEq1I7iIpsV5S7aJSnsB4ODyIyCM2\nnFkTFF+q6pPZuDFfGZqQboUlkLJTf7YhXzRWjmFg5vSHKCJbYXnnoH3TY2xR\nMe6KstYNrYAzQH/2cVcCEdzVQUc0r/0rx2DUjuL7rBC3L/Mun2EMVANE9gtt\nTQyv\r\n=FOMv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDjLtdctfkXo16yIjS8jVudTuySe3KUIR01+haL07aS8AIgNWiIYKsYfqy+6aGEsiMBWIZBBB48SjBLP9phvvSHnFM="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_4.0.0_1539277144734_0.8547585529833006"},"_hasShrinkwrap":false},"4.0.1":{"name":"micro-kit-atlas","version":"4.0.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"813937475f7a96091cde3da0db1500b0f2eaf398","_id":"micro-kit-atlas@4.0.1","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-vFn3+iIrI/banpYBA2PNqox6XUWr1vdx4YM2aJEO+TMNdI+dSnXtRXz0AiCnHzmXC/UJMMbQkZxCL0KhfmEczg==","shasum":"8f678b212799a2964ccdd3c88f2bd0fa939efbed","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-4.0.1.tgz","fileCount":102,"unpackedSize":449954,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbwFERCRA9TVsSAnZWagAAhCgP/A0LTlX/BXjDzRtOKPcN\nrvtlw0jTlP6FBXbzsF5V7ruej1bvGAZ3JM/9bwvKYjHhCwFOmuoHTGt2VUQn\n496vjmUAETrBmL5exDSqGERpyEbMlu14nBOqa4Rt5tdlvfYUSa/NmUlsB9q6\nAnRkqt3f1qqL20k+pChG6YVry8oB2m0UIlhOhNXk9H4RjghzUoIBr+pu9mez\nCTrZBVUEEQo7KQG4X/W1hrqpeGmvjpSyBnnv0UI9P9zd/M5KZWbORqIJIuBW\nrymIQIWIpngNVotPTDCH7g04GvJF0lgItnKldXLNpwsiBdWYSBnf0gZ8bVm+\n7tBkAZvmsGcr8a+W95AdIRCthl5+kdjK8gyVPCSW4hGcvlwTaHUzxJzJtyxw\njy8Ek9mfXNRGakkOjGbfUcrKnFbiwIpy0vwXIG7M6iOU0Z5mMi7DJkB4waaL\nKwf7p6ExOt//w5pqr701V4vyRP6aIaNmHTy1M7APu3Avq1ZWPBXEyfpe4lXj\n00uCXftV5vdQIVBG/IIfez5IB57iWThdbL4L3EhC0pcd/Fl67zUiseSSwIFO\nMQGHGEg2kLgvr++T99jx9ePLED8igOSUnTIIkPWWDTQjUc+/lfy8799xzykh\nTdFmg/04u2ConOC0ZARub8ar8+/0aCjrVcMWVqqYw0WcqfEpKcu6KFKL04+i\nB4vm\r\n=pRee\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCrwFmtAnDJkHFVEExxRNb9+lfStNgDU5xBlu1MfY0R7QIhAKAGHyOmOp9Dvvvg3RhLguhz2sDABM34I23pjRncVOgh"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_4.0.1_1539330321123_0.7053505637600397"},"_hasShrinkwrap":false},"4.0.2":{"name":"micro-kit-atlas","version":"4.0.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"46a9bb5dff89f0702808ed83f9b6997965185b46","_id":"micro-kit-atlas@4.0.2","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-nJaCgpFli60oiqfFazIyrEZmJrkak4SZ2/cuvnQ2Arxw2MLTJjVHgr4Pks2NxJns8dZyMLHVk3BTMja4AatTDg==","shasum":"2f62ea31854d0b5dcadd6cdbb43bd106a842f5c5","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-4.0.2.tgz","fileCount":102,"unpackedSize":449956,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbwGYeCRA9TVsSAnZWagAAZLkP+QCaBEhroMS06SyKNO9w\nLqLcOw/xB6/io91qbAe6HUgamL0AnqPKHPu0v6Ne+SXF1b2R6QmC6sqYdLzO\nVKDhXLyGVhUnloebcdzGUdTGszgjOyjuRvwlNbXQPyV0tjIBtMFdbadC6abj\nkfEglj4j+VEke/mPkAcGjPdVIX1wFEYHNHBVJo/ad52BsMHRlcfhJ5zvuxMP\nC9pFI2DOlMbLQWfEFbOKZTu+AFg0xH9U/jS+BdhPMZ6C5RuVSj3qM1Ro42Xf\n+1CCb3fqz/7kyk+5QdiiWB81tVQxVGEK4fLfewkb49MVD9g1julz9u3db3aw\nmEM2y30dTh1HaQnebRM2P6slUvNPT2v+y5UwXB5wttq0GuRI/GmLppgvaBmj\nmYcuacW4LTuG8ZFLswzm/kCpg4uo73h9YdrUUTlVeZKONPwG0A8LFS2MrKWg\nUppXsVW7JxrX4EAQbjOrllFdWH/Yui8buoFqP6rUObqkysz52B5CWclPEX6i\n9RTPixU8IKreCIC5uLT2EyDUUIAIjOSyA8uPB2/WlFb1k4aVJUUNL1W6UlXo\nICjk/YQpuseHSAZe6/1tKDFxwv37Xu6vbgm8Yo3qzNR8XJx4kS7xOxbIcIYP\ns8b05jdczmKwvd8UuuFBp3+ulXwhwlzhc598eZiI7KkZwnHM77uF0nQPA/PL\nJAFC\r\n=m8VJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC+ruaVNp671HbKjcAg4cC6MrBVzI+6ESvs46iwctWOHAIhALQ4OfLwmbEB8Z/jXB3GceWZyVevafxtR+VBn7DBmrRV"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_4.0.2_1539335709749_0.9913046611538752"},"_hasShrinkwrap":false},"4.0.3":{"name":"micro-kit-atlas","version":"4.0.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/dd-trace":"^0.6.1","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"4eea20c4ef163e13a341f1a495a89a1a4de831b1","_id":"micro-kit-atlas@4.0.3","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-3R6zfaiAAkcstfUeAajYIWoDmiqXHvaQefWYvMpfZ6t2susSY19ZeoLyCGX4T7LAoznkg7yMSg2Dv1GuIdkHsw==","shasum":"87e4504dd10b3e7af8a8257b437b6b3a9b87b8fb","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-4.0.3.tgz","fileCount":102,"unpackedSize":450110,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbyfLtCRA9TVsSAnZWagAANS4P/0crmyz58UoNs3AV5sKd\nuMtII1sgU8OwYRkT0pCBOYq/lkmYRJgOmBLUfD9cxNzB1wN7p188ixa5UqJI\nki26FB+szQ7XVEtpzoXAHT4ost+Pr+VDsVCmMKWMq/SFVbehwvH0KSPvHHpf\nK0d+x3psm8TsjC1p+DFeHeGXsYD6DLb6bk549CDL2AVvMAfIIO5cggcBDtt+\n3TIg8dP2hGrEptrN5yMxPmRRxwycl8IBMBAwrlEyPdoQVGRiB6X8Hdm95h6g\nxedA0F9CE2k63eW15CisuXozLiEgbZKjs5PtYF/RI7HhL03Vb42j1aeb92kQ\nqIgvn3l/bTe60RHK1sFsmblH790CYBd+YAWd3RwXIbG53UUDRx0zAfUZbwh3\nxktlUUFG+XvRkeVDnL4MnQr8zIZ2HHAb0n+6+mi8zfO+3EXFrCvLuCylO62y\n6Z8qvmTve9+53B2YEfXplzUmyh43Sf2SoFIAfWFzNS+VG00K45b7j+Xsgs2f\nMvptou4zyOHj2nP8Ay8YMo1p+hmGDyXfISpujhZrKc85XRxXUH1OtjrO/3tW\naKKS5pf5yt1HyxxU1JFQNa0p5pHlio2GQ8IFHr5ThohoVe4IMT8OjQk/V9yT\nFAkjB9LtWG2RIIXQjlBrplOXPBjyDxTmykP6fFL7O7F+1Oj6SUrXV0Cf8z/s\nQ+/V\r\n=LG3d\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC5MY6/QQpUyQkF93IdABm5zwpUghyQeA7WNU28xlYplQIhAP+ygi9z5LxQipFQxlJh/1YftEXDW3eIZCQtNZZ7fDpv"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_4.0.3_1539961581025_0.9563023147956979"},"_hasShrinkwrap":false},"4.1.0":{"name":"micro-kit-atlas","version":"4.1.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"38c8c9852e1c8074d527bf3580162077c0ae2e66","_id":"micro-kit-atlas@4.1.0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-3GQLTbdFG2YbthRBEeU+QGqCCzepp+ouf+CqJZS6ih9zFVHFLf8Wwv883JmXLyHnS7jnHXT+QEzEHZNnn01GNw==","shasum":"f19b3377b610dd4d2080e3a8ed2b7a4e52228dbc","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-4.1.0.tgz","fileCount":102,"unpackedSize":464553,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb0D9sCRA9TVsSAnZWagAA6HIP/RdDLclBz8M+dx6lPK4o\n8jimI6HBD3aGxUITV9Nghlmuf4ZnrWGwW5cLlVX30vMgNDmZIWxYsn+IY1U8\nVt5TjVxLvON10SBtd8GQg+dJelfqWCLebC7DFi5cP6IdYwB/YP38C4F1u2zb\nBn4vquCWRgt9N3ckvXkvuWkUyQ3knKO4QUi9oEOsQ3NtDbwYZc3GZS1m7HTN\nGLwrbChJg9lEsdjVBQCDUcuqwuhW/U/jpNpmjW7qoY6DEac1BMEa0bKkmYpr\nqyb5K9QUFD4eUJ/FRDJFxOP+U7UssSmcBp3cenSt7Ox03nKVRSd8gwuaAfen\nx4Q+Yf4d2pdYlnzGS0miDgz2iglBHpTqPCtTdX/aM2D4/79SZFuEbFwpMtU5\nijXRQvTdbSsZgeogEEfDO+RJqrLSXVVXvj4rR7M+lX1IUb/Am7XTKn9nlK9D\nz/fRq6b4bjYW2q5qxUIvqyRSVLyEoGMeTJn3tc+49r4iV/0VqYqPTgKbfKkD\n8EEYinnC8kLMfYDpP4wMbctMyFJStfRusYR4+2IVLRsf/Q8UZPWQJrgQ8sbK\nLiLbN0sDaPpyXwrd4yUFIHliYXKMAj8GOO5Tx8ov5h1gixf7lr3RQAlO4uZ/\n982Rnbanh47aiAnhGi3g/ivDKLF63cS+gtyIqcOCcOHsYEp5j0/fvqId9uWI\nq5Jn\r\n=WYaD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCGZa1KMXsjTTO6qSMnjbSmvh4sQggyjLC8IX8bvoIV4QIhAJmqmv0xzy1ARflrVCgYHaMdjQOLEX3bTLc8RdWtLHRu"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_4.1.0_1540374379784_0.42843330983478967"},"_hasShrinkwrap":false},"4.1.1":{"name":"micro-kit-atlas","version":"4.1.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"3c5667a5b9cea734fb7f7917d80039b2db8783c8","_id":"micro-kit-atlas@4.1.1","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-2J/ea8j5tAXmUdCNqLyV9TO7wQEr8dnuxPJQs9qkvWyH6gZPr4621kFZKKMwMA6dxOOV+I1FGtdozwzyBlwa5Q==","shasum":"222ac61072c943b79dfc2f130f8cc77b0bf08baf","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-4.1.1.tgz","fileCount":102,"unpackedSize":465349,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb0IErCRA9TVsSAnZWagAAZ2wP/36ZYVoaGQ9ju1RpKvn/\nbwdLNf5/6Nb+L8gjnFVHEtbNQTUjF3zfqtGcItNVHjgbcq1Qud7KPbDjp6Xh\n86s+7J+mGXwRKS6j2czUUqbi9wDvUMHlA03xdWU25E++rQM/BvVM+QMW92aF\nlUTenivX6HADBibP5Le8k6WeS9ip1ZG4DX+GhpMXvf1ZrQQGGU2W71AsgzGr\nYJuHEzEakqSU2VkBxNhS0H9DmNdnuC/XRfLkXb+nyZCSduvOxMG060RjNm3c\n6hsnxdtxBBTuCHdRxTzVQ7UK6iVC/tCzEPwLJecjkvNPtLkONOpDjEbaJa2Q\nt8JUZBygNf64afQgoD8zK8btqUBb51B0Y2094xeRVPVVhzA77/b7A33D9ggS\nOMc2EZn3eRSJDZd9xAjVYYJn0DXzeilrCgPknSzQ2jkGxOs9JoD+IJWUZpbI\n0G8/9hB08As2iT8t1e0u6EYtg1BN/MSFIFA3ZDIzt2Nrzw5w2FgRBRWtsns2\nE+hRoCr7AYkCrt8JPjOWnfr8SmG8SxUqwMu4694qVZK7V96WgkftCnPH/WZI\nRF/RYEzK9FA0dmNk6sqeNsVdmU0BfEyo2ieEAeIzmdPL1CRw3LOa4XLltUBD\nq2QYOKsDOVAnDmH++pEDXNJkIZ5rfzk53YKP14qKn6v1HEWXPWaUa3dCbdTi\nD33n\r\n=0Pps\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD1zsmSvPM7DKf3POs9iTpCtCcQZPpiopddHjb8cbWQzQIhAJTAaGC7LcEwgRcih1o8mHmVlxECpANQZ1EGxvAA4hah"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_4.1.1_1540391201955_0.2855459444869133"},"_hasShrinkwrap":false},"4.1.2":{"name":"micro-kit-atlas","version":"4.1.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"d2258239ecb0ea5c403a163370493dea28348223","_id":"micro-kit-atlas@4.1.2","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-8CV7bXIUzqKXXAoLIU9hfllfB1F5XXg270eOFz8aUKbJTncXUjtBveNGBEMey0gxHCGDRfeWdOiCXg2j7K/rug==","shasum":"c04f9d25cb155570767da86ab1c400e84f3800e6","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-4.1.2.tgz","fileCount":102,"unpackedSize":465278,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb0IYnCRA9TVsSAnZWagAAhgYP/0p0Iazp/fyi44I8tyiD\noGtGplK97I7mrHChOSp4b9HS5NnKz6L2IWzLPAtaMCixe8fOwIkfkecgU8tO\nEYSRdQvptRPSvakfc3IGmWL/Z+RNgqk2+BTBP6ZjVlFIvXuR5BwAdIBPOYsS\n7GSkiymFPQ8JjNJsBnj5mBpQiXzPlIkh6dhd4bYFZGDw0TwJ9tyddItLxNSb\nPA4aJYKQuG1ScHWxMCnbgHdWgOCau7fRaltIunlqAxJ32wx9jqTcwhztDaXg\nkm9ZpxTwxHxzfr9DCB1spAgpsSDBTPKvGqDYaMqvG9AnNsYZGaUSraMZ4oSc\nmXtGmHMwE7jqh9HkLdQPw2wQH+JrOga6RMCnCleTRuzSZjIMUgRmDkAlOTgO\nMGDayGcnBVEEPcUQDlh9WmYmCMwTM07LgL5roNgb7QCLeObbtJR0E0r9bhIP\nXba//L4W+m+kgzGf4E0lfiEoFefw8ME6SOC5JVL7Azcz38V/j3IDtDoJzW0Z\noaA2rJxOdheH3stADG2thUl7HYdPlwJu18e+y3FTPTxEZ9Qvug0QYrEnRgiQ\nIkmDacl/bQtkPdSCwWHnJAilAiwfQ0iZGZdOAn+iGM0qPySaITclq5q/qjx5\nw18hvMVpCJ4Kl5cuDbYSM1+ROrW4mqrh7anZb2HdcuCtlfAFXIMunAUpcXNs\nBiN6\r\n=VG5Z\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDhmpqDsNFkm6dLW+CvT/T7jB4m3DY8g1gtUQFPdXwgqQIgfHppbqYChPaiGEu+gdgQEwtfZhKb14pOPuj6vS36Yz8="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_4.1.2_1540392487298_0.10550272175480635"},"_hasShrinkwrap":false},"5.0.0":{"name":"micro-kit-atlas","version":"5.0.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"bf0563e4f1d6b9ff0e6cb370c891e760d992af75","_id":"micro-kit-atlas@5.0.0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-TdNfjsWwY4LrSYNYsIjart2ZN/zLMs3sxX+ojfhGTcalQQVvr90uO+AKN+oKoMyzsE0Xw1KPXjfinwd0T5kmEA==","shasum":"5d18e67f5bdda98fbe5964b4abc7609720921714","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-5.0.0.tgz","fileCount":102,"unpackedSize":466643,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb0cxzCRA9TVsSAnZWagAAUR4QAJF5ky0N4IEzGiqydD5L\n6P/PZzYW7eddS7AkX17h8DLGMIUQYR61B90TQ7YTo9EIPWdsyt3FeT3JqszD\n4yLdZ3gHA7eRIurZtYxXI/mjD7Glo7UFQ++zIu2Xncox4AJd+8NrYI12m2qO\nhSmnvCUwesCmAlUh0C96siJPzJqW4DbYKY/ejEFLEz2Xbgwr1kwwbam3P/2H\nKE/vrjSSH3zOB1s8+e17sMnXNgNP6mIrRXQ4zX8EX1a0RLbdUf3UrbLy4dn7\nOYeOrYynMO/qbrJXWzacehwG7Hjorrx1NzhcA9EMSHnrsiGcDEENYBqU+mFw\nFPypfomxS9iuX5S66H7pQK7YaeZcdq0UVgAslqWPMJlqIuPTja+xpideITi/\n6G9gAEQdas3pDx3ttjxaEVCmwSOjaJekdwbPdhOY7B+qDoMZG6Irn7w+jAkS\nmOyAQFaesgEmNPxrShm9o0Yy3xPc2TKxK17c39buTDNB5zhaR6NG0gdiucpJ\nsc4P71guSfWgMHqtKReEapnP4/yTnCalRAqhFB4Wid9Ey/+9QymkRu+vfYVH\nuYpL/JqNNOnrkAsy15GIUp8oJUjrkWNn9mp1lVq9eN7tICpJzjB4jb2LoE8Z\n+MKBUXM9BzQIeTrTMS9wl/685QVdm1BF7QIKJT+fGZZE8nyCl23CHt93/P8X\n+CSg\r\n=Wt2A\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHxlHf8tPF3UnIqVsPUfVClP3aBfXoyYxmon76cGJ7NCAiEA2TkKIhA1ULUoTNulUtaifFpAIRX7WX9lhBCo4+Vn1WM="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_5.0.0_1540476018803_0.5346356342964249"},"_hasShrinkwrap":false},"5.0.1":{"name":"micro-kit-atlas","version":"5.0.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"1cd84de2298289e202fea9522993e081fb6fba23","_id":"micro-kit-atlas@5.0.1","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-/QeEPW71uxGhAYjJNJboR2DRiVQIChxoAKB2VB23rK5dzkk7SQKFjwrx9nbPBI93C6OCMAKJ4VaLHhWcbpTjqg==","shasum":"0b7a6a3fa029ad7c405c76e8a57f7a3f3719d3a9","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-5.0.1.tgz","fileCount":102,"unpackedSize":467098,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb1wcWCRA9TVsSAnZWagAAByYP/2qXfBCU0SebdG5YluCQ\nTvB5gvVwau1gCVkDavgboV+1sBY07OV1VHgCWv78hdcgRC3m4BkUu4WsW2Io\nObZJeoC9Jgu054z79PAnUHcpxw7Jd/OXYe/1mgQ1oPrfATjeGhL87tQTySiO\n05tkWBjdvACW2kDD6cjb33lOfEyjryKrz5Qxq3vhTpKi3jiKduClQMhRq7Ne\nrMehdCtRmMMxv5sopksj0Zvpvzl6djnFD1cqP9LTRiXGbvkfy1MRJoaS+s2k\nXz1CniXaBgS9842pM3i/jMRS9f1x0fZt9e13OP1FbwVhFRgSMv5Cdkc2tN9y\nvR6lVPat66E+prkJZAXD4gVB01MrCLxIVyMysUsYXdi1JFxqKytRfMBQPXrO\nGRbA3juIGa/KPzsLWNTOjXNBdXTugU/iVU80u8hd1rYmx8T8QxvuXb5w8aQN\n9ryZL3vhL6cumE7t6eKj7z17ku1VlbWP+PDjihUlRxNPphUfLvWiZY8Wvb/O\nNmcX9C7U4cCjn3b/Z4UsNSR5xe/uwnxfx600KgLpoSjzrQ7q7fx3JSVA9C5R\nfEqsvE61cPE4zo5OQrAeX6Cx6s/2Aoxq3oAbnO1M21kWAevIHRRuOMr/cNUd\nr7HJHW/pxVcNyS1ZCeR2YadPhPS6kguwjDSQ/NvY5AqqzNpBqhDAtfKhJhVT\nku6+\r\n=JFMd\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCR6L8VFmRJk1FjqDTESyA5a3oy/C/eW1R7OglW56s03AIhAK1zMj4JP8L/9LYMoH0TFcC6A8ubYCV4ZqZO04LgvQUO"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_5.0.1_1540818709709_0.4352879892924151"},"_hasShrinkwrap":false},"5.1.0":{"name":"micro-kit-atlas","version":"5.1.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/dd-trace":"^0.6.1","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"cef594392e60f774361e8e5109c9cb751acb2b69","_id":"micro-kit-atlas@5.1.0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-+VfK37LvPwQcZln7VTPIL9Hdl20FJV0ViRAhrY60wAhxERDDKT1qtNkItYOXQ9dl1SK7YQaEUFxS0WpSBT+qzQ==","shasum":"53fb5c3d77c149d5e2c99a4b1ba68d3c344e7869","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-5.1.0.tgz","fileCount":102,"unpackedSize":467374,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb2Bt/CRA9TVsSAnZWagAA5lYP/io7byTcns6irR5AtCvF\nsV6JRMhgtrVHgwxMtJLz1SEcgEIIev81JjWO9cJdbMPAfUcmLxOva/L2vfAD\nST22d3p57cAfH0hEmtxUU3eB1PR52DPlUdIrF1dMcqQTBHY6BoPbbPEeLOGX\nnIHSxeFhJVNHPvkCovDeCz+Ms0fjKixhQtn+mGljSynp0O70PKI7XBmixIZ2\n3Rs2Ll3HbWhMCbb2j3kWLRReNqiwDlwSIgO6k1vZKLti61O/MkGj/G4M2w1t\nUKw8UVBI9or5eXC4GwSR6f1WKSeDfPAxBbaLzTa4SspjwROxZpteMLOhWZhI\ncREaXKDd7Vg0E11OnmdfwoIML/DDj8vf12yeGdw5AyeS+H4n7ocQ53IIVNXI\n/7MQ3jty9T7eCNk2kpFi2wMzGBBgxQMglPu+o+ECN/EYv3oV9fE78KVM6LA8\nP4zKfUYo1Df1G7MygFouvolngxtKVlf/urHdpa2vg6PVptICDjpbAH4RoLMZ\nM5GtILJllGIbj1+n1+U+SCWyHZL1GnRPJbInP9TyDoW6InunmCi/ZKBfNvLo\nGLX/VIZNPKgVWAMUkzcmlWGwcQLGcSEx6C5xKeNt5s2RW9fE4LcG9hrUxFGe\nQ3hs27l8s1uMLTB2v2DXoFtf/x2w2mANVj6v4B5QXSFWsYiv7ceLPUQtiLLF\nfNqS\r\n=ioBI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIF23MRrKUnpgMwCEIkFT629TRRJy0LP03fRxgr6aUHk9AiBVowrUAer/uB/nJfBDL80ImBh2b9L8SJRK/uw9rYWpfw=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_5.1.0_1540889470284_0.2506356999059951"},"_hasShrinkwrap":false},"5.1.1-0":{"name":"micro-kit-atlas","version":"5.1.1-0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/dd-trace":"^0.6.1","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"6ca7be4ec297d034fea83992aadaae033ca92f65","_id":"micro-kit-atlas@5.1.1-0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-tYRX9aHhQXDYTPd/ed/gQi+vC47JDW+3E7YgY6d07LZkuUTn6hcyUF+QR44adYP4Vkh7H1oE6uVJCx44MC1hpQ==","shasum":"0d3137266082a84e35ba4ea46dfa4815a204f111","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-5.1.1-0.tgz","fileCount":102,"unpackedSize":467407,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb2E/aCRA9TVsSAnZWagAAqScP/20cPP5wuPE/wxwuib97\nHpXTJZpFbzFCnAst5ioqsSLBAes3DeOzZeEflzcVhKHayW9RhUkA7bk+ftl9\nRaEX3tSzrezNn0kHD1Lxmp80jRImLiyFinMXC+1VopiME6OMa+qB7t4BerUx\nSUUMduX3mFdV9p8C17DE+GLNSzPBUAXxGOgim7yTmYDdDnLFmDAAad37HhCI\nZHJIYUBWd9WN3Ps6njfK7TmLySijgffsAIZ/bilKJasIlyEQ0Fp8tECljnLu\n1IFEV/PhSe5nBdW0vVbR2aBZflvEB5uhawneDvYfTHz51rObMrSGamFxQ4R7\nzpjvfjW7UVecmmBujGJ30s/5flas95e0OktZ31INcXCW8sRz+dkw2h74/H1w\nEE0/8PLHxxrpkB+7nWpZzKSvuD+pCfZ2m+R6xNtQmVtqD9zTEN5VCMywqAEI\nw3IuwKtIj1ml3gftE+b2ekYpXe1XsawVY+uiVi7xV8icAZOZLxuiOPJLO/DJ\nMCb9btfAjgP3nOTWvsnd0D4JoIq4y1BBXU3c82I5L4Nh26+KyjJAKM5PBX29\nd7YtEEnujI4V3v9jZab84CRt5VB+xy1xsK3dsRXUi77umH/Gjh1/xxzifQsY\nUmDU3BjRHj9DtpAIRxrQ9PFrlAPGbdBQ9VJtJfEfvB79TM/uAR2sKuiGJEEy\nUIdc\r\n=HHPA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCCv4nFrDICT+7caZYNlZydNUOad+DBNmU3/s6SpIIAlAIgd8hT4HHk83RqcmaBcfIBBJ6tjHQ6TrPiBedXjFm6HhY="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_5.1.1-0_1540902873216_0.6496866737849123"},"_hasShrinkwrap":false},"5.1.2":{"name":"micro-kit-atlas","version":"5.1.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib","examples"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/dd-trace":"^0.6.1","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"2f6baeada28f6e3ff38559de3fc26b50bfdb5092","_id":"micro-kit-atlas@5.1.2","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-U+oM5Qqev36nS5aI2EzeNhew5Szxbk5GHsnh/WW3G76xrlLcsKVCbkmTKTenDTyXVbKywRv/3XogB8h/nB4iUA==","shasum":"b0305082c0ec511d322fd949e609da483c544b3f","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-5.1.2.tgz","fileCount":54,"unpackedSize":125482,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb5F5pCRA9TVsSAnZWagAAxjQQAJ1PIAtC7NsNvc4qzNB3\nw9JrM2xBIQSbb0GJpAs0Gl7geDoJuOTw2Oo25uJPBWoP/3HcJzQbB51Oh5pF\n5ijn3haZz5CJ3UXs+MKqA1hjoavG114Gko4aLrfrRW6ujQjzgJwq3/3uUh1Q\nRaJwEflWm2Jd3Urxh7IJKWWQEhnyWrEVcXMJ5J2dXR8/Xqo6v+vYNC3DG6GV\nRrf+kvTyXtI/ZXS+ZMsUrVPy5sPXXPcgeyd4AammkpX0JWrTqjTvx/rKk+Rt\ngKKjd8I/3KGbSk6wu63Z4k2i6CwGmTheJ0oqZOpHaBcjaPE6DC1ydafQfU8F\nQsLSrKrpNNpiotuSybTRiY1lwjmnbZuUXDuApYWc+0GcE2PhhplFn9X4AL8g\nM9psBYqF8lMtmKwwfkTCFiJ266Jw91csggsAPvRvn4LIgOos5Ye4+Bq5BhRU\npp/NbCxyXOFRdN+Kg7C76Hiyyz3ZCT7q7e8K4804PB73wMU1W38lj614efaP\nGQF6wpDDof+qgFPTLPoDaqrebzHHHGAoiImP9aC5NjUcjNOnBllu4AKW4PaH\nC+8F03xFMur/E3OgJUZ5C0sATY4FG7FRSpTlmXE+lyZz2tyJferj/+gpKu+d\n8w+D6wTNcTPeto1AyRvnGEIdOFvkI44Hkoc70HH3eCEcLOJXwVqVG0mwqLzP\nPuaV\r\n=+vzO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDbKbN7vOR0XOXwKJjVQFZ2W9Xhe9UzyaLCVO8BZzZz5AIgffUMwausBSQ6J7y9Pd5zM3yne3j6MTkhDg8vyPCc734="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_5.1.2_1541693033003_0.19712958921658452"},"_hasShrinkwrap":false},"5.2.0":{"name":"micro-kit-atlas","version":"5.2.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/dd-trace":"^0.6.1","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"738377a7772637b23a09399e80bc6308fc350208","_id":"micro-kit-atlas@5.2.0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-kC9khJ7+G19t0M3bE5Knqate5ulcx1O6a+KjDJDmyr+myjpZ6Om+qX1AbgY0vr3MuGOSrvGEC4rZj9CDnKXIcg==","shasum":"4687e2c321f14042a6c5ed9b7f8aba17bd427654","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-5.2.0.tgz","fileCount":59,"unpackedSize":128338,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb9RcXCRA9TVsSAnZWagAAU34QAJAK/luACjR3dUy9SXW5\n2zC51IeGPXwazWwp8dfKldFdy7CNuJ2B52LCvAxsJ24QhNFPInBpXLIPwj39\nYMf5udpDlKWfZgyKDsakDqdQrZ6p/RSWNWeuXtS2X0/6PCt5jhSMkt45opj/\nee8jeH3Gf8PdV3/KNjF6Y3ANZo7Dx5NtgLX8ivwok9UkMPsIXg5lI0CtYT8n\ny4mafmyot9I8jlG9CmvaTbqffGjRaIfyh2Iin3NLv1RLXtsYhJYJDsy0tL2I\nqxN/K0ClsYjNBDksLS3+GdELBH2eKBckVLMKSETgzuV25NgC5+O1+Mjo0Isf\nSojHezypDfFBDJ7zf3EJWxcSyD9V5uV/xGKpvTdN4njDPZ5P6vniIqtHCcsD\nn3ReyVybIYrIvp3Yn0FA89Pvahe3bj/FD1JhKoNsUbkOS88PTB78jRVeqosf\nF8axxGa6L2zMT4Wr1W+y5oAnjCfMvPHtpRZTrKY5YV0k/0Uy1H1HKN29f01r\nPLWaEbjE1yY1eGqRNwnMawICz1vCKneksG70hrbMqt+8tWfFcbHd4kihnSot\nWtuGd3rL2t6ivTAaja28y3Jif5c/cPjgjTNfhmEI8NqOIP+uMq+Y1GSuZKKJ\nmvVsE10cUGdxY0CjI5VnfCKD27+A1TQ/Qp60IY+qAZeacS8dnMYPVbL/alcq\ndLCA\r\n=f/XT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGRwKZwl+Gxw8UsZYzfGGEmjqf8964N3++gze+mdEm43AiEAjeLyOq4WHmoiaCi2HJxUy1hxTAQ2+D3o/CWwUcfoHU4="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_5.2.0_1542788886482_0.5875064257253471"},"_hasShrinkwrap":false},"5.2.1":{"name":"micro-kit-atlas","version":"5.2.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/dd-trace":"^0.6.1","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"8c7605e73ae5e0b05b8fb1d56628e3272e7174db","_id":"micro-kit-atlas@5.2.1","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-UNO7fGjDsCdmryXLwINcXtesEJThqNmuOVDC/IqR+65m9lvvI1eAMyy/eGZA9+iFnMB2Tgr5/B+7QYhB/hudww==","shasum":"b3f65acfd208b80aafef747740a1a91c8501afbf","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-5.2.1.tgz","fileCount":59,"unpackedSize":130998,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb9svKCRA9TVsSAnZWagAAtVQP+wdkN3CP3G/wfsfcs4NR\nWm+6THC4iW+iXwgzrrziJrJwIYDv9S+P/3dssnzHqD1//kgco0rTov4QsoP6\ncACIMc3iOJAanvnmYzKJuYD5LQEQ6E8ZFsfV/UT3BAGXYISSbfwKLgubsHHT\nbKuteInbQITAveK8aeaELLW2PGNyPL8OD6O491aFaolZTTeD34o5DRAF7VeL\nwh4hNHcTFvuEtwox3oUkq7C147pA99lQkZ8lVCODVL09//JpmjRz8c1yR7B+\n1VHJEUjX3gQ2mYurtNm8RZZyfWGsB9/tfFAK96qelBzNqZ46xRMAN0NrkvL8\nSrJ2rTOQkQvrZagP1JOtrOi37OjQQCBGvVd+SeHdLpYCyxPPSSCHyFIX/iF3\nXVGDdMNtQltsAKGHbYhzVgqyaIn/iauusLbvywcsSjOCXcRtNo1Wuo554Lqb\n3CNER34t1A48xep0Ikm6QZGpbUok1+gFWa897Fml5E51h+yZPm4zJUJvtOT2\n1wYzeeDWh7YKijgyAf/uAyc/wdU09zd47a4dr1leTdSv9PKXxqb5HUBDVCkZ\n66GE55B77OUOlOUOmZvTXcy7jRrtpc+IY+MwF8tDqsrdIMzxWcQX1eAZl2uR\n1yUPH0V/Xj/pPG0xHlH6O8F7/mKMhIIaGqo2D71pJLP5V9h7kRaoRzBEiNG6\nhfMP\r\n=Y/d6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCEUotnpDf3qTlzeHlJLM5yRup0CtKU611So03+h+uBgwIhAIguAuXuynsqmMdZ7TFFz2ZWyMLePw/OPgrHQalN5HVF"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_5.2.1_1542900682070_0.22060791469468466"},"_hasShrinkwrap":false},"5.2.2":{"name":"micro-kit-atlas","version":"5.2.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/dd-trace":"^0.6.1","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"6cc012a2f214667cc450fc266e49a1d7937a7b85","_id":"micro-kit-atlas@5.2.2","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-0WCRDl+GjS88h2EAaaMeLR2IJM3rGHMdHNbf2dleSrvL0slblEfCr+evVhcf8Ph0aBAfe95GfTA3eo35FsKweg==","shasum":"6916e912f599f3b6607dc54a12e3bb034484f72b","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-5.2.2.tgz","fileCount":59,"unpackedSize":131040,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb9/8/CRA9TVsSAnZWagAA3CQQAJe2o0SdqRHJdbnuSbaZ\nFkKiQVBEKXfQEeQWbEvujcIhD+BauOBZO1s24ODU/UtIb4CRdKaKTz/P4dde\n9OCCyjbDv4jzweP4o9J2Q3SeMq9AVWwhP1VU9Rs+pW6LcyF9WpCfuuSjRfAi\nxGBaRjbjLZiA29q0TImLQGiZfjvlaoIC1+Iq+p461szLZdg4R3BzldSLudXZ\n5nV9b6Dfgqr5V/e0qMWXy9gFSIGDSgEoZZmY5Gg+Gxnee9R3kSnhclzEPNud\nigEMuFy0E+mzfuTEMxVRqrJOHnjM3LAzk2aDsl6rNUuJFFf3hZ+vXUmzDGax\nsFr4eiYXK4cX3ooas1dgEdr4R4pzFt9z4jXa608KMY73aOdhSfOmmVvoKJ/P\npnNddE8grCr2RjzD+nOTAefJdWHy/tvxrIKwF7FwcYdjLI6eLD6PI/RZ/STE\nNlKFWeEQQNTegIMCC5HT1F2Yhia/EOKl6ZNhi5RMqsgKotLWA7OsCdtQ/MgB\n0IXQ394OWO1kMmTR1S8N33KlJbaLn4nfkpLn0+hPQiV3ifZ+CfTzGcw+AnbG\njQO4MzORd2hhaQLhMg/X40+zmZOiGx8wTUwz+6/wzXdpzZlXPgx4snumD9QL\ntF9f2d9GiHGl1zbYZGe4F9/0ADIQV/fSWAy5DNhQHsGYM8ZLDH7DW9bke+e9\nvLWz\r\n=n4LN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDOe77/jBtdiTe7/9yW+soSGdPsNpXmsjlaq11eijvAOQIhALVCO76ux90viouf2sVNjCt8kkxao5PDg3r3Ta3XKsjf"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_5.2.2_1542979390817_0.3130307759599933"},"_hasShrinkwrap":false},"5.2.3":{"name":"micro-kit-atlas","version":"5.2.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/dd-trace":"^0.6.1","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"a78033c5e371e0da0fee27527f14449e5df9830c","_id":"micro-kit-atlas@5.2.3","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-BN79ANdVp6AvTLkBmlt7amL8NK6na5ul64bc9H5UcCI6l8iILmCcDN5R072x2L9o0t8WRExCoxkN0tjPdEeV3Q==","shasum":"a244d9d43bc41ba73e09713e24adccfb46ac70b8","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-5.2.3.tgz","fileCount":59,"unpackedSize":131733,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb+8A9CRA9TVsSAnZWagAAE5gP/20Vl2Sr9N+fuqXThu0j\nwPf5nMVDd+pCROTW2PmeVM7Vw/KFtXP/tEz0BMp63W5QbxtQJ0os8vGSUr5c\nCSFvEkZP+tLXBvvpGUXFwL+ZMhpx9SWqGD+uJW6y00tJnH2Lj+dBDM94y1r+\nDLibZH/MzVZlUZWUM+nFmm03RSU/3kbYJezh75Jvt/jR0JxfNxtOJ5tN0tiN\nWdBmVLRq/zS4FCqLl+Pa0Oq9oZqTJUp1OkNKTF1DqhsC4i6D1xvsrEE8oXaH\nmKzerAOaTgGhp/q7OrX6puUwfWz+V9l8/Kqf9KdXjfQJFxaSAgFikLgjakZQ\nJCwYsJHLikQsAWeT0vobO8Ii9nfdJ5tcq4C+jzpG6DyKaW7MEiKuAIh/4GUL\n/N+okYWYsQ6c13q2rJve940etHlIf4mbEr5I5Q+bMkbZNDuXtrGIYtvZzGUX\nKJm7wLHYle13xRLU4Air35eiqojRBYKajJOr9bwYrNFqLyPn5vadVZktkw1l\nz7eCfupzuakCtEjoSX5IaP6f3f1IMmoHNeyK+m5JzsBu3SHPfPc9I9pU8DwH\nt3IY1ZXw+D9MyYVil00dmtzgPC5gakODju+4Dpu1k1vbIqiVudgAb6zR/XH/\nKPs8JVpOkRVBuNwifzVRArp3YGbaLvI8d0MasBVj9mlKsCUJmqvFc9BDSG2/\nzZJz\r\n=nlF0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDk91QAwaIi4WYzEGJgoIursSdi5WtMt5QacShZOwApWQIgMQiMVG5Bp2Ar86TSHc6Do9g3BqVEipL5dsKMvt9iQiA="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_5.2.3_1543225404735_0.6765850594550307"},"_hasShrinkwrap":false},"6.0.0":{"name":"micro-kit-atlas","version":"6.0.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"3b675a7b9f98ac6e03b4a71360f0e684f5a639c7","_id":"micro-kit-atlas@6.0.0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-n6jLNj5jHJWjFYayOgXwHaUGF0rLUsWYEvVd2MKu7a0E2+RNNucBohrASM5Kuv0bHyJ9FDrixTYwrN0Dg/l35A==","shasum":"36832f6fb76c7862f1558ec8a6d75e8a12d1d5cc","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-6.0.0.tgz","fileCount":59,"unpackedSize":131726,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcAPi2CRA9TVsSAnZWagAAzWgQAIVEpZejPsxtoOzHCGai\nwB6umnm9ohyS+DTsFB1h7DYP2CUgIJSQelU8oMJivYzstiDMvLHj5AqvtIs4\nZK2E2YgqBw+t15+LqBIimoQFJhGQ5weOL0f8LmYzQQXD93qYhKgdkTO+VuLQ\nePorwdv6i5E0Pw0spzxTamPigAilSblOE1f0lft/sUcsGaXbRpwAGRbCjAV/\n3eDI/D3iSwKuUMDGNFgoJhBM5dRbw+ShxTHBvOe/lnv0M9wmDUUYR/INpQi4\ndASYYVZ4r+d8zWlwceoYKyZT4pD7xq2qZ/E5zy6EbkgmR+PniLxTuTZFIGw3\nHV1j7ClVsqqiHkU17KXnAsTRvk0llJGBbh0NMaO3rMLU0Tl6sSS2ANBhsQ1y\nzyRHl901B7SxklSEI1cL6Z4Ex/Vt2nWxbG7O7HJ694hyuaSemDxODNlyCP1U\nxbR915WNDbbNgrwFdhenwGeFxUyt5EUAzDUUdtHceX7vufYzZamRfx4mSV3l\n7XkOnkIqVSFTJCUNnpJwFpA7WfxBjSgagQGxhwxyWMnvUE4Sj4e19+nPs/ql\nRWPHC7J7+mCrLiYZIHviH+imQsGljFBUBrKUIqW6/LvzbGdhFy9Nd080A6+5\nKoRgqgWiJoMflkizoptRZx5S15vKMb5XLmcQpFgE6z5mw+L+Lb55e0B2A8V2\n2mqo\r\n=N8Vj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC0kJv4b/38b87KwCWtnQm7n03ymCXJKfh+r776qoF+QgIgOi4QzYqCYkveYaiX+tCPbYDZOSpWFOX8QWDOOyeK+uk="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_6.0.0_1543567541629_0.771863138809139"},"_hasShrinkwrap":false},"6.0.1":{"name":"micro-kit-atlas","version":"6.0.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"bab9509b5bd2a905a8d49b7961eb28243dba1223","_id":"micro-kit-atlas@6.0.1","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-sa8doAVrpeMfVWC/KlNxZIiim7KHKp1lUNVGs71Gf5uLmmYvs7PPWGQSPXSdF3pFNujdejE1+prseetztkia1g==","shasum":"1b7c58696ec76fd639eb180e9e1d6619dd3f6466","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-6.0.1.tgz","fileCount":59,"unpackedSize":131627,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcClkvCRA9TVsSAnZWagAA4UoP/0eYMy1Q+MSQ5XvKDuHW\nsYrGqNJLl2XwK4djaNiq98J6GJ9bITsx0ucpevXFfaFfjwYKDigAJXe0wNKm\nEf29dsgOgSKGf54oYgWCnxiSignp+ApJx/U4wagqAELY1Ddo0q51eldXP5X3\n7XNMfIVssXyvg27qjyfckL/LJmnZETeXxDKXKf62ROW/nxP92TFOskHgWG5N\n44vxLckcmZAfTC7ATRZKFkdiYPoc1NjlXC7MgrF5S0G4ufbRkN4wUU8qy2CT\nKraq7wYZdHTfjjJWOGL+c74RsVb4MBbjDGJAvoT94HbKMRFZ0wtbRxI+u5l1\ny3h9Dgho8zWHK84GpVuz8XDs3k6YPHjEGzzL9588ekArS5iHAQp00u3lVmfZ\n8uaM5t3jpeB+wfVofOC3SS/0l4i8yoK55nwU4Veuu1XeBbhrOk+EH8trd1cQ\nfNCyMBQElTJEO2V1mwUZ4Lv8z6x0x0yRbhipwyUN6k+/tFOwE4VL+IfqKrjn\nc/JRdrQj91jD5UoKpzqU5uAQWYqU1R3M1hfsPGkIJMjK7RO5+4VgWgnen/km\nG1rHpa2QH6yG7weRMoNpx7qUQ/G4MKLWdVE6pTlBcWFAzjpFCZMnse83NaOC\n4o/7orzYMXf7YAmA+1DYSvYitUoa9XXYjZtWpZd/CEdBdEu1N7HRZzehhK53\nHtvE\r\n=3dwz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCPMxEKoMBH5FX4bwwnkFKThlrxhwStLMs07rGe8Vr+xQIhAKEsRXmJotm/cfOm98A9Tpij/L7+tsmcjHws8J72hQKF"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_6.0.1_1544182062720_0.4781858398003582"},"_hasShrinkwrap":false},"6.1.0":{"name":"micro-kit-atlas","version":"6.1.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0","tslint-config-globalid":"^1.0.5"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"93d90cd7812835910452bdcb002b14430bb00400","_id":"micro-kit-atlas@6.1.0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-K2AvVSBLbfypKflu2mT1Qr6/ceqA5/ZbXJB8EPvOE43Tpsp5LkagE3N85vT6mxBpp8TrCOyeS48iCDYP31inDA==","shasum":"d264c35a540dad8a63f856ceaa11b03dabe1af5e","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-6.1.0.tgz","fileCount":62,"unpackedSize":134916,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcCojHCRA9TVsSAnZWagAAl0oP/24AQ2HkPtLBpPxGMMWD\nv/P3aa24DfpxMayZfIMav3JKMxqDDuzT/rvIgK9TkFLnWipGqWgHn54djajz\n3Xi6x9PJvHRj+2/p3hgyCDu85mNQLcaqX+UaDPkWmSiTo/Oz0LeOvoSkYN15\n9ODhwF5I3pqUlfkhm8Rr1fn+kFj24g4Efkrf4PCTqWmP4J//dvJvt1cpbIVg\nxFxaqERqcHt/u2US9+2atY39uzO1rYh+ficu9+WAi7gzzYiSQrSuYGH3Ib5t\niJ/2A4PW7dDoy+7wbbRJVcpcCo8zI8maaEGsFNXUYnazoEI1da+H79hP+sGH\nlo42kxalORSg7ibeEXAPlZmlqTCTAlluOiSmcaUXi9pGGLogb8xEdfHZSzNh\ng5Xyhxo6tcWGvURcl+0bHxAENXrx9A7zTIrNViXtf4o2s1MVZPE+8k2Rcijn\nrI1eFXIMgPMJqynb6OafiYpxeWbuYabL2NzhPe05rzXWOlx8wYR4ZqFk+1N5\nJtslxOgc5W1B79OtDFQ6MuoFpMEKLmPjxzDmQieeEfPrhDu7dtX1hFOXdCJD\nyiEPFM9oJ6pTidEdPAz0T0sAm9MVC62eI4Va3o70Khmsc9vk4+Bc5qyJIF/l\nVMZb90iBKCtr7jq1fNdV6UeIDAmhBQAI33gzqv8szo0mHgw3VLi/Ggi9XdM4\nwqfd\r\n=oGuL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDlQD1HNjXOKA0Jn6i1OxRdJWSsokFGssQTusrEA7ovsAIhAJjcx/rlMlpMXeoT7upAO6bqbCf2r7po268xEB/7ehwz"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_6.1.0_1544194247117_0.11549047176151994"},"_hasShrinkwrap":false},"3.0.59":{"name":"micro-kit-atlas","version":"3.0.59","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"src/**/*.ts\"","test:unit":"nyc mocha --compilers ts-node/register --require source-map-support/register  \"src/__tests__/setup.ts\" --full-trace \"src/**/*.unit.ts\"","test:integration":"nyc mocha --compilers ts-node/register --require source-map-support/register --full-trace \"src/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^3.4.2","nyc":"^11.0.3","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"^2.3.8","sinon-chai":"^2.14.0","source-map-support":"^0.4.15","standard":"^10.0.2","ts-node":"^3.2.1","tslint":"^5.8.0","tslint-config-standard":"^7.0.0","typescript":"^2.5.3","typescript-eslint-parser":"^8.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"nyc":{"include":["src/**/*.ts"],"extension":[".ts"],"require":["ts-node/register"],"reporter":["lcov","text-summary"],"exclude":["**/__mocks__/**","**/__tests__/**","lib"],"sourceMap":true,"instrument":true},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/elasticsearch":"^5.0.19","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/mocha":"^2.2.45","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/sinon":"^2.3.3","@types/sinon-chai":"^2.7.29","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","decamelize":"^1.2.0","dd-trace":"^0.6.0","dotenv":"^4.0.0","elasticsearch":"11.0.1","express":"^4.15.3","http-aws-es":"1.1.3","hot-shots":"^5.9.2","ioredis":"^3.1.1","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"7d5268e70fb385a30bd67c249318aadd06381a95","_id":"micro-kit-atlas@3.0.59","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-vllvN1zVADbXaMvnsnMgwBjwAAl9ybkUYp6VxA9raQSMOxbfgESPQb8AItHYPxsZ6w0XJzHkLJp1ncKsowA3Wg==","shasum":"89fa24ded46adb5380704a35bd53536b1a438127","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-3.0.59.tgz","fileCount":119,"unpackedSize":418386,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcCr03CRA9TVsSAnZWagAADhkP/1tBpMeps3Pk87Kcwl7R\nYSnE0A93lu+1+Ezv2M3nFO9zGT4qox3TupK2sI1tCAO9l1CQ+VMvSomoFJjd\njs+aRZP6iRKcTn6V1YpnPl+ZvfOqu24ZkMWxgSyQA9ZGI5y6/DgheOQ7NaYk\nqq8asRDGB8qeZH6abAvhHyx/VUDtlVojAdkr92ytEIrlHTahA1GWqg7YATri\nAEkDSCksXxfXBIWkGGVE3FkgApPnquxagNUQrG22wkMjxRQF1kiyHu03sCbQ\nIpbqSNyLAb87+pgfp0YVkNsJi5nW2nHW6TTgXRTXQPCiAujjYLwZvNDoXZpI\nPwZF/I0b33wAvtufbxPQEJmn2/R/VOC29K1I78C92YcLVpKwdfF+gyKtyA3b\nDodmmMROo53+eFXIS37SrhtIxjKImGoymFLspvPIKRoTpUgxOkuW4+1eE0IC\nzTLqmiOP70tUi9Gz3UimG615Tt0BWtPm9WdQqauqRo7CcAi8PC7c9pGKsJKh\nM4c2jrlMLE56mCt16KGYg5yaOGpDezUax9nemBD4K9A66mK+aRiZEcTX+hdB\nFshoBbsjHAHP9OKw6tglK361KP4/34LtE7AsBdfI06uTo4FhpKW5I2n2cykS\nh5Ut9zlukos5O9IKz3wYTP3nwm88v/A5s/O+yiqwdz47KODo5R74XM5ehJDY\nnQEo\r\n=535J\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDLAdqn/o7RtG1HsRcGnkrTIFCWqBbWP8ks+GoYFqEWJAIhAJ+6o/vLOVHmgIZ71E3o4Zs1F/wPvk7SZOaZ6SDYKLY1"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_3.0.59_1544207671237_0.711913809153504"},"_hasShrinkwrap":false},"6.2.0":{"name":"micro-kit-atlas","version":"6.2.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"12e10224fe3f524faa5c081a12a500058e73ed19","_id":"micro-kit-atlas@6.2.0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-QYkoWJkLf8WtaeT+XY2IRQcMApK79wSvZBFNuQB3d3s6MnIJfmBX46nxDGhmHwMC70t8HSJUqk8UmgXSs51Bsw==","shasum":"20f4cd1bf2884a8978f9059d36b6612966d1a04a","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-6.2.0.tgz","fileCount":62,"unpackedSize":135713,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcDoS7CRA9TVsSAnZWagAAfecQAI1BxXKpu/7Z71gLbRtH\nIOhpQgElIXGza7LbuopdKiEqqtXpA64svcdtIhIcGEECv1UIo/fi7Ji2Ic4R\nBkuddcHyysHg3p3y9mNympRBPh7DuqPBNVvZNJi67cCYlgxVXpMH8LUNwlvk\n0CxnMxaXIcGH5X3LJ34yObUndn9yvh0wT8TxoSm1GeRSuQEMpWvOc41FMIhz\nAP+xwPiJtFtxY1jaUNzA1vYvSEQ4VgJHnZAJtHGp8EFfzYIjCkrwMvoGkM5Y\nzU/Gans+sG0IlsmCbSKlRf5CHuU7bevs/9nVLLNoIApX2Lmy9wYrGp17Hs8C\nT4+2CEf/Du4/2KCk6F0RdU+3LBpXX11vBkp8j/jCtv2dQLafstVhTSQc9FMZ\nDlwkWmnJpZ8ZJWZJQa0JnOtlXZqQJ6Il1K8/+OH+PCn2FkvrHfMykVf/hSQN\nU2bhAh22Dgz9+nXQt/ZGc+ggtluccGE0/kKNTNQaH+eUcEtLZntn859uskBp\n0FT+TqGonsVjx/p8VlQrEeqZuaNURz9NY/EBTvdXce8z702w89hiQhdeCwKe\nVpbLNResKOm8YE84t9X7fIGZDi/Lp5CXGsZg7R/SOFK9jaOhv4kwc+gfzYMX\ngnZX6LY418GO4mT9BPBYxR3xcdC864Hp6JXdtovvK8QYfWM3pfqSGfF4QVBX\n8du3\r\n=TXrG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCWxbh00pCuENbrcz08qlHZqbin4axGbDHzbudSTd2y4gIgITaiZ+1g6H4q49SgXdchudb1uOAUNdTaNr6cwnzysYM="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_6.2.0_1544455354756_0.7577827312955365"},"_hasShrinkwrap":false},"6.2.1":{"name":"micro-kit-atlas","version":"6.2.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"b91450927ca315d5f45bf353c3177d873e53d0d8","_id":"micro-kit-atlas@6.2.1","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-80QxaKA19XmLnV0SBxSvX+1jxi/FvYIrgj2lLF45Loucq+pymu/iprPAwan5mLDL5wCzTXBeFl/HlxoUP7bm4Q==","shasum":"a64ff43c62359c781043d65af1831cd81089ffc5","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-6.2.1.tgz","fileCount":62,"unpackedSize":136011,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcG5aACRA9TVsSAnZWagAAbIAQAJbyiyc9hJz2GD82wPMA\nMOgOIiyIZj3vX9grdrC5gRVraEp41W87OQ/sf7XSoWDktu2KyZeMGMPLDA8d\nvCsOFeAUGR+io5iPI3YB61BrbmptLJn1wrXM3N09GX36GZNd1YkoFy5bo47/\nILtlt5t5jzfCk0qfbozWwVT+XOnvwpKXw+q3TjPk4wv/fm6cGrOgrxSlO2C1\narIsCcz/D9mddTskfVc2OAFN9mLyqtCMpvpt/YK521g+UCZJzTY51T+qzLj7\nQ084+pv9NAkNTvvoVGJXUu8SisFnwm6YR46rqAyOOC9Nwgekz/7/X0iau5Rz\n4puoWLi4ebYulNDTIHGh14RB5Mc2eKPdJh9L5seGzFtyXutgF15oieAYmqmN\n9WldncjnXbJaRzzQszQg7wM4/u1oEN53QXtACkbs4Z/f6wRC5+cAdeeVT0bM\neYETXn8SL6HBokNV7nbIIzpMO7cN7krtRoZTIxXKJaO4paYeVhZTKr6UmB/T\n9cnE4gZzy31d9c3chYrNN3KKfNdYLuT6ywxJe9rFnRVq/90MrJHEBs+G9yTk\nhzU81/cdHoWSPnd5Bu5xiw7458LqXoPfI8PI0axNC59FDF3N4aR4aWrrBuVs\n5ITMJkoZePyMXxAWZygWJO/JUr6rc+uFPtO/Co3W5Lm0lAUrhxgZa1NOYVbY\nGb9W\r\n=3ssz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCQ0RgeMrvERAGpZE+fswMtS+EzWPZyNa1WwT14vETJzgIgcOcA6lpyLwWAHmDi8c3CmWavVUXGhSxwhLPUu3PJoSs="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_6.2.1_1545311871759_0.05504746114293324"},"_hasShrinkwrap":false},"6.3.0":{"name":"micro-kit-atlas","version":"6.3.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"6420f675bffa74201a5eabea9c2ae8900b9c36cf","_id":"micro-kit-atlas@6.3.0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-sALwCoNLUTyXQ9sY80FhkPgIfayaPgAzqbCMowxoTazTWbJpgqsbFPqsBvhSRAygsWv/hglpTaclxqyQhZKmAQ==","shasum":"25caa4ec3b7d95331cad34e01d197195bc650442","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-6.3.0.tgz","fileCount":62,"unpackedSize":137525,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcMx9pCRA9TVsSAnZWagAApiwQAIJ5+Nfj1jpdOk0J0g24\nuP2z/JW0DwYwqEqTeRt9jp3JQUR2AEaqYJwSIREOJhN947utEmtaMMdyVLsO\nIJYpR8klSif/0437j3YiGXVDqWQhZq1yVc+ZYMcLWBv9vg8GqwqsQRABwFSs\nHFR6p8iLanhwS06rrIWWDPQ0mKYubjgwnWmuYBt/3mhiasIz6zL9X67OiZlj\nRhDlM98Xkt8eDFOGKydIu6eJ7NNaj7UHUwkg2mrtYpD2CiUjg45N1XUSYgKP\nbDK5LVDlA6fC0R0rez7QOszIxmi4NIm8kmSDY1pxzjkQTHotLhG1keQMN5xU\ngOBuuUzzcOW+dLAKPVy/rHuYYr1sTsS56VFQuRLkAkxenXzFoTuvq9jhKNFk\nfE6FKNLOirGKpm2IFmf78iEbb3u8SnAC1By4Ttgp1fGFidsxgJTSMk2ETRUH\nW1uky2cMPIm7KdzuY9zd6IVmWCAx59h7e/jOqZYcp+fAl9YTOGs9OVRJGXS3\nBGceOUP7+2WjTnLK8QjflHkDbCLxEvHN0+OGajRCq2o9zKSHJ22q7nacXArP\nxj5tr80FeYYGf1UAoC+EQkixQ4fPbwt/eD2yIDVfxV7dnlHXctLOxfs3EEcI\nIAlSSL0ANHJ1lTJMkxJfKWm77qLtGqGBzwuD+ESDIX0jrMeertYLLTHOWBVU\noBbX\r\n=rk8r\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDU3EIW4/CoDQ/oeHUwaJ8EhVM7gG/VkZSz88iZLVNDCgIhAJm54Oo5mXqCetn1PDBE2nnEpVMu16MT2o/ZorK7SkfO"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_6.3.0_1546854248839_0.4450060773064133"},"_hasShrinkwrap":false},"7.0.0":{"name":"micro-kit-atlas","version":"7.0.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"dfbefef54e46e5199a7867e53becbcefc9573208","_id":"micro-kit-atlas@7.0.0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-CTkGSyayxricPDeAvl0ahVOSH1S2jTpm9F9gOJtbdfqeiKlc5dVoQetT7rC6Gi4trx+5TfO1FxY2ZwmLO60DlQ==","shasum":"87420bced8adc7d402439867b4ae369f4d66654d","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-7.0.0.tgz","fileCount":62,"unpackedSize":137522,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcNGL9CRA9TVsSAnZWagAACG0P/09cnGtlRIPcsBrxiccH\noeJ0iZ1B7Oa1iRkV2U/LjO3xOLpuuu/ImiZtvCw/JgmIaVRFqu9AlUUnmbb+\nIbAbu0E/tV/exwe+j+pbIDEeW1DtwIle1TXfuUOSYMA0WXVkZ3bG3cADtDub\nJBDCyKwfUdbDzvCKYwy109TwvGqNnmKeGTC0qcMSKEeLCFCcN4guEl+HVVAj\nXuZVlsReYAoZICiCg1SrXlAdDoZzQY/2fwL4VFVf1r4Iv5QSMmVyGqf6q3RV\n6Wnbcixyi3kYyXK3pMomCN33i6w2dV888aTOTmmT+ewB2ovcflkpXhfKqBVR\nQHcYmKT7NDMA+e/Pb7qAVUeTUfLPS5ZzCXQRKe2VJVqcayYIrpPlWVkgMrUr\ngEfXTflMOym7j8WGLzJdN1ryxFU3znA1I3G1mXrqK9peM4CI4zLXOvdZ9/87\nkYUglxdDiTK9vL+DMnD6+NXzJ+H4v+fA+MjasBtpAg7yuMae+gZEh4yFPVaF\nITcd4UsSxReLQQCSMIdV1iQr4SiVMUyiXe6jMwvPJdHkDOquAfAUydH+hZHv\nVN95aC5cFJLFSNiVVOX+GWa2UgbtsNaBoLp1w7QfP6MK3bBWZBt1yaDClzAq\njEmCa5C7Q7gPuTdrZqMYKThLvgwXPEXGGPsujS1LWy4DtOQYeciIdZJ7U/DH\nQJdi\r\n=MX6G\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD5Tx5/Rxfvy/oz0+AvPCO8yBP4PpgydsOWrhkof1QKbAIhAMFIo4aKIR2Hurp7lF00JYdBD0FKPnSFY8gVu4zbVSFj"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_7.0.0_1546937085105_0.8527141319326608"},"_hasShrinkwrap":false},"7.1.0":{"name":"micro-kit-atlas","version":"7.1.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"37f31753d7343fead964f24a57745305dafd1ba1","_id":"micro-kit-atlas@7.1.0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-oDS/i3Coumwr2EcjYqznxVEzNz2zKBG8DpjAusvx47sokKL58Q8Am7TGUpp9/Y3VxAGPB3j9SU2o+zB3/1W3vQ==","shasum":"c96ede77ab5d62a92cb880ebff99026d3faa5974","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-7.1.0.tgz","fileCount":62,"unpackedSize":138279,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcNHLwCRA9TVsSAnZWagAAId8P+QHQ7bI5jTaO4VtkVVPU\nsqvvY0jfDrNKMXFqIKv3yMZKP4vOn3r1uxXBRkUAfMSaLOLJWGrVwDD8+kMY\nopAPHrIiyHgHqHfRunftaYN7pYKb2yC2tiPxon6ZEq4XbhDEBx7G0hSsscTV\nKtIY0kiJ25VgcwxEi9TX1JWX62pxgUO0e1BAG4g0z0NJBcc2e0eUo7WtFoRZ\nevebEaEhpyRdUBRAY6m87Z/fT0yy93Lnh1N/mGVxukEWsCosIkjIyH84w1cn\nL4QWtHkbUe9eM3+5XIzU0zwOIAkmIz2Vzko6GtT4UWNA45Th4Ohqg5H7/2v5\nNneldAhNHWA3pXdZki+UX506cYBG5NUxbWWtRj+CAFMOpR6kTPC8xX/4UPnS\nQsRaJVeWl/Hsauhiv42a8YATgRcMdweQ/2VGvHt0hgvf5DpPAvxOyFG7OdPv\nwO5JHdUnfdxst1aHU5R7s059N2pbfvOwsIGGu3MrZuJl6yM+dJkHWwHAv/AQ\nwQy+EzHoOcQhyZgXzr+oo+DS/QH+OwowjCX9PW71buZNv3cEiVbbIHqFZDwU\nun8K2ULsHFZ4BcNYGL572fyS5kzjf90kkagpp19Y4qJ09Ji5Qc5Cb2m9RyQg\nPWOLWeYywTVKZ54xvKTnS5xdDS+h43GaQyIg6hHUFfDbAp3tThr+ZVOPJVd+\nLjjd\r\n=W9V7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCID2ffsoAh2BcRina2KKgctmDbZKNH97Y12ct82+Qj27xAiATC3OWtZmKWWwTglJs2WKCcu1H8HjugN+gLzMExMPWlQ=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_7.1.0_1546941167363_0.8608177452334802"},"_hasShrinkwrap":false},"7.2.0":{"name":"micro-kit-atlas","version":"7.2.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"^2.0.1","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"8ac89c4ad9ce9ea4e10641a0f2db8f240f5f9822","_id":"micro-kit-atlas@7.2.0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-zjfuOKrr2tqTz4JkxZEqcR2BGsRSgq+/U0/hYeLOCtBSuvx6aG2dNAaeU8hUdifQj8I8C2P6CX6U4sxOJTt/yw==","shasum":"529f4ae6315b2a0b8c39475d9c373411e7ca4319","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-7.2.0.tgz","fileCount":62,"unpackedSize":143613,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcPKW8CRA9TVsSAnZWagAAm7YP/1N37MCb+7gattW/zDgl\nwHGwOgEgaWK9tcDudGbfCzxPBimG9MaUWvC0jyJ1zcWrYrSJp0LZA5kxVhWF\nv1HMSBP3aAKBqUk4jG/Bu9RF1NYVbl+mFjrR62DnDPjJTp0thrCicKOf0hqf\n1Wgwt1AHsOHR5mpB7NOSWkZwzGCubhbTcpY8/hPqqWxuQyiEdbYMTbUnmA2q\ngnYNuFad4JW7937ib98y0mZBNBkq1l4e/rEdTICANGcgzbTNMoK/tHKbvnTt\nWD6nsf2kFqL56wSk9xdEtaJldZZeSO3VBZ0UuO8XEixgmVSD1ipmbQuFom5T\nEA4AuM0C/QyvXq0//8MOnN3EqGyRJMfkJTDxZDVo6uq4W9DlB0QqiHzjq40x\noO5LEejDwAnZSj1pX01Abw+JLVqqtZVOiuqaL2S6FZ/3Pw6NF6NNffoh9Ldt\no6eiZl9mcXrbLSGCVZNh8CS9utWTFWEPvQaibY5cj9rBgHmn2GDgrzb9etha\nYPXtnGWgRJYNj7Y6jrf3e1HPBQvLxACaxA5fM/sjUb2TXj92nG88UHY4zsG/\nyg/fuYd5HxPMHVJSJSPGOqnaG6+GX6jXyb3tvH0K1KHGdrhdBL8P5jG6/7Wz\nbv5MycGpIhRnwrBV2rp4PrUax5bscgZHU7N7qZBqrA0dPHFXoiMcXg1APkvx\nrXVL\r\n=Hilm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIA+2D91pQK6ziGkbzRH1PVx/Nd8/0Y3cXT/ouUw+tEBHAiBIV0/67Fk5iN22p+sQ8ub7heU11RJsbk0cG6oruMyiAw=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_7.2.0_1547478459304_0.4342381995377598"},"_hasShrinkwrap":false},"7.2.1":{"name":"micro-kit-atlas","version":"7.2.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"2.0.1","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"17e979999befb43d5e4a5cfc0addea0677091c49","_id":"micro-kit-atlas@7.2.1","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-TwhHdnir0Fz5oppkVEBINknt1sdWUnGm82ztp1mTa4Kt58zXokx9VNR+WI6sbL4gMkcxog///FvPs0Wj9/xMmw==","shasum":"b31f31d99d4bfa12358d42a48891012c921606a8","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-7.2.1.tgz","fileCount":62,"unpackedSize":143612,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUuh3CRA9TVsSAnZWagAA1a8QAJzqWHVN0GhZkjrlG68q\nvm5IKvu8r/PiMD1JC7DzS62jBVPs+76cKi6Pd6xCYOICvkXttYxTHb7Tmv6a\nHvyHRujCbsBAn5c32G6757bX8DKSLA6JmULmtVD4vFwvTUOcM/eh3UlFQVe9\nVkURrMvI8PRYKv3nOWvhPnoEIxQTbxB8DWU6wiaRVCh8HNIGPJJ1yrmI+1dR\npe6QA6aRy6aSczpn/3OhpTU98alsEC0dNbJBzF2S/7/cTxq6LA5vIFWBOIKv\n05xECn3DrlLGx7PX6k0vEUe/0cInHZ55Y859NzXuYAOt9ZuHHat9fRXkxrso\nUeAvraClxLGZ09sT8nDTvjT61jlSKrwH84/L8ksn9KzJvwSfmo/iv8OzEPNl\nxDRfPPHrXusHk1ib1JTM7W5jVQx1JaJm+EP8PSlApPj9g8KNrg7NkHDE/p7t\nPHx7KTyGQOEiAJD6JHrR6N6TbOPPKJt6jtrTjW2vNWohn7H3mzEpL7vUl1DA\npGO/Yw3MAaAXDmc5FnB6Y2JFCYxC8FJ+dfteBes9HobeA6jDPPhLEWVI2Hi4\nvz62YRHqenS6YqnUMrHABkZwa4BgVWSWQ5sijFDRN1+1GW3iHUeEHXlWO0O6\nkPI84TtYH6ua6pepBP7y3v6184QDyWbOcJ9AHJQ7OehxMoHs50NBccogd44Y\nXrxh\r\n=rY5O\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDWATJcDYMFLFoNBesGyZ9YfW+rlTstBC5eU/eNBhQn6gIhAMwYehUDFoLt+cMmQTy/d7OC00dpxFAgMwHgrX5cbm91"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_7.2.1_1548937334655_0.9282795307919574"},"_hasShrinkwrap":false},"8.0.0":{"name":"micro-kit-atlas","version":"8.0.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"~3.0.0","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"211d5bff254b34566ed6fb2b9a0d13252ad9a218","_id":"micro-kit-atlas@8.0.0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-L89I9KYaJI/luumUddwVPsgDqSnopWrVINLZM+RuyDHxNgz0/5H8atFE9u2vgu/eZtjGnDkaKQHWWDitb3tmug==","shasum":"240a4296f12035c14d597c7557d98de76ee53b63","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.0.0.tgz","fileCount":62,"unpackedSize":143102,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcVC9TCRA9TVsSAnZWagAAjeoP+wXyIz9VuesUjUMFzxR2\nsDdLFA+6LZ7U51BBl+YCCx+7ENIaOgcuGtVyvFwtE0fyxp6uabYwiPGDLj2V\n8/fBg9feSHcagRMKMyurdBzhOGmVvC135SjFf5D/KjojY1mWBAJwEqfvWZgr\nFLWJps1Dz+noWDYxSGouArpiAbxNypb0uVMaHQR5PhsnJQvF7UqNagcqXkQl\nIOL28r9SqKBi5X0/2pbTnTwTsPnuZ9B7lBRJdVkHPJudBe9kKuuP3rjIPARU\nN34LiuSFHV9bPzMCsb77RONkrndNLvSTkgeIGOQ0tniZnVIOzo82Y7lnnw+F\nXM9Yk3GNzFDajQyos7ZFiHccIsHlIsUukDbXG2AfXcSciQwLTxx+PoamTSJ2\nq10lkckcVNJojDOswInY7ITnKXhE5ZgVdJMjVczzeMjSeFPS9c6HFsioH4ZH\nmNC/GazHBTxhzr2GiLgpgQ2b8WtRBwyoqcfAZU7cYQLb4EMVb+bEMzYIKfQ+\nA9YNTuvOb0D/tolxc2L7dIOrEwuFrAsrb+b4YT/BTkJqXau8ft2ErCxqFyYM\ndNw6Y625StT14VlnvDoutksLHqZOytpAU9JKiM6bQK88vzbFwzkcNRPVSjiS\nw1mI2EzLWf3IN5cR/o8NkxCGWMDknu8yoHZ2RtIod/iObg4f7v71vLn2dSfl\nt5RF\r\n=J3Cm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB3Mqko1hQWfIvFYTSE7DqIO+FqL86l4gBlGGrh6zCjaAiB5mL0+OO6IzvgNPFPb7F/Pu0tCkp/kxs5qXK4AERRA3g=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.0.0_1549021010493_0.7668045725578472"},"_hasShrinkwrap":false},"8.1.0":{"name":"micro-kit-atlas","version":"8.1.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"~3.1.1","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"2726720203880f08f9d6bc76a982ffa796237af8","_id":"micro-kit-atlas@8.1.0","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-+40tIULLX7PoHDIqtbxXZyT3XVO79iboGATLGvobc2SexvQsH/gYeRRJD/dfnM2f+V9zk1yaIjqLBzSJmRSFjg==","shasum":"d3d6f45f956a3fa8bed9ade85d5fc45820d13254","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.1.0.tgz","fileCount":63,"unpackedSize":147707,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcWqCXCRA9TVsSAnZWagAASPkP/RWM8yvOwOfiu4dMutg5\nOT1LqI3NT12IX3vQ9y9fzvxKWxkTqykIbKJ1tGlhEhnrYh2HwqFKHc4tCaV5\nGf6fqAQCweWgdgAZpBw3PJIGm9hNBUyFzdVdjGET25u09niS3III4iXCS3Fg\ng0SQXUYjW8vQTFsBXjs3ytNoP4x/osMyvAAu5sUGV6rn+iEPqB/pMPhQmoBx\n+hDczVcThVLsEHIy+pkbv1F469xsPO9fnXgkH2vF9RjSk4aPT5Kv96EBbXli\nASA6Q1wfKgsKzoqbWoAQZ4UqQFeUHq21l0hhnoH5wbvBJ/rSGoZOJVXsa71j\nqcKihiDC+bOzohxo7xUESIN24slft2FM+lpx5dnzNhZiPPmhc0IqV36ESA7p\nXwXXqv9T7z22n8jUt2wF47UNkUensal74YcsaXkujozC3I9CjswuTR6UA0c4\nwRFT8hBFV8gmFyQqoxLI7NpceOS30n5I6KcpqJyJV7DQ730DUpqwHpk4kVw6\nHyZA6D6ZpybTRg1jeSuN+Dhq4yD4o1HvgzebrT4QbSrwrJCt1blkh1QWMm8O\nFsSf1kErN+4iu1zPf9rj7Jo95bxTbOIX9Xwo4yxLEnSKzYI1WH/7Ygt1mGZ3\nRqcQuFQSyfnetzM8EVoDbH7lTaWvl+TIG5unqRIZPjRKISkSfQ0+kZLsrGbm\n8aMi\r\n=CFpN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD7ViXiuAoZBJz4d452UY/3IttFrnBpL5/E/JD5LwRpswIgP7z9Wa82ouW7v9eRB10gtMLC6+bIraIOrAN/4ttN2qQ="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.1.0_1549443222432_0.26140125771467027"},"_hasShrinkwrap":false},"8.1.1":{"name":"micro-kit-atlas","version":"8.1.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"~3.1.1","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"9e943a1341e777cc2ab223c93864ae4b4a4c960f","_id":"micro-kit-atlas@8.1.1","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-3MnIwyDxjhUVmQmqIzYhjGNofufdgyPKOeAlCkNfF5v6OZsEZHP5qXrqtDjaGCD8enA/67DHoJUySYOYw7smPQ==","shasum":"9ba6d4a43a4ef4923415b999e1811dd46ddc1fce","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.1.1.tgz","fileCount":63,"unpackedSize":147571,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcWwmHCRA9TVsSAnZWagAAif0P+wdzy0wbHZQr01MNo5E2\nTrJYE8lWE7USLdE3V/l94lmjsJwMR4Ktrk9HlqyVKlcpWQqXanZ0uhPaEPPE\nQkiNY68OKCrXuLL8gxDO+ecZ6eKJ0W/fpFGiz5dFcaiKeKYQrblUYCfaNtPj\nTn8DnXYa1dPNPKz1eKUJJYFI7zx9WZYWoyE7rTnXiHzrARVl67wvXyUJsUHL\nUPW0a1xCrVrMp2bd5JHrDgikvWq9ME+0q/4/R3vSEEPcQEIHllteFIW1D1pP\norWxTdSzH0VlveQXE6dg5mydfqb8OkWUv0smciqN6ha0YHR/ydk/W+x+rmet\nOEvhVIhFu+ClahPKAGW98XgkeeVIbA9ht1p8oV+IWnlALx1lO44hmNxUkH0z\niKuqncC9Nm4dOJY8z2jv4GMys0LpPlqA0GC989Dy28yjTLLZpvVwER6TgnUt\n1wYPc0i98qFXE1C5NwVHdbrV36OvQWFp6kUbT0GJB1fhn8GIiw6X5m/egWNN\nl+7mTEwdZ/c4P5MNVp7ubgCuqmoeolq0K9d+ivXcXftVtcwU2cYKHZ/mvEz1\n4s0lR9KXxa9TSv8vXLIx5rkhF2zuUavB3RNdA4HdtKZEQFboOjcFagdK6ign\n4veyxk/yNQZSa0lEqBX5XJomLQlWDdL0IIRFAlzd3VLEr9NpuSNgkMlzbRsv\nIb6m\r\n=32ec\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCcIuZtJusgLS5dimyIv0aNTxue3/Fj9mRVSv7Qg4JsDwIgBFiwG7SUJvHlYBSZGxOCkE3M5QrgsFzI5q4f71ExnFM="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.1.1_1549470087178_0.8918637282799684"},"_hasShrinkwrap":false},"8.1.2":{"name":"micro-kit-atlas","version":"8.1.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"~3.1.1","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"94c835d8d8a4b187a7c49133c87dfafb613e8a00","_id":"micro-kit-atlas@8.1.2","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-PNIsREuI02J0G9alnyWDeuhcJfmdDs7yCH6idcI1TGJNPTHvIfGetlkscM5C8Q6IEd+ZeJV/rXVVrKobrrix4g==","shasum":"3f6902466dbf0dd0927f96e94f60b6c264da6433","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.1.2.tgz","fileCount":63,"unpackedSize":147708,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcXA4LCRA9TVsSAnZWagAAMZAP/2CfFul0kBjLRuetZU9c\nEmueZCMlbI1PkRPlvFZMP7d6O4W26x5NVW4LfDqvn9EHGhOljgG+YxAYJGfl\np351zzVQBKLirMkGtU7HdgucloFjHlNfDAMWMAkKPOLhbJESHzStTgL1fDYj\now0wmzWz/dZX5xVsbtsAldSjw1lyU5plPynYbVmmIZynXh4lb8hYOSFFE+3v\ntdlkoTVY0lfiYTV1C3NJcOeEpOAgk0d+4XCuGjnMk2mvRb0kRoypyejGum6t\nig9IU9KkUGLTLVGTEZNnUUL+yqB19RFrv5co8ESlyRRA7RewJpgBBDvlOkLg\ntndNdjk8n+Xisp+VCaM2rVgAcET+InibYkRTKwJqL0nvO7VRaJR3FA9NGasL\nrhqCPvtgvMUFZCpwxXLB5k/hfpQxVbKrQJZLvyCLxaitL2Hjru/P8+azoG+1\nL21Cg/vKATjs9HGgKU7KuE9ZCSvovUdT2C6TcuTUuZVU8vTGe2Bxd1ALLcGN\nFUqVQ1HGd0E8fK+HUDmApvjdm4oFrUomyC0iYAZvQCEgTkI5mTeku32D/Fy9\nmtk031PhBY7zcHbFRv2A5jmz8PDzwohCf0bB5AlEQNHLK1WKJvwD7fQhhkrk\n2xFIkwzs0dsnuk79/KkGrCQUH1NxLpH9h1IJVbP4dZHZ4VolQOTwQKfrkpT2\n2Chx\r\n=q8l0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDl8oqWLBgdGFuwaCH3uXfKU6A78JaIxHsbj340tGxiogIgYPmW9UkQEQ714Qd8SnrXekj5pqYojfVOrsQT8TyETXA="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.1.2_1549536777780_0.4217394102061325"},"_hasShrinkwrap":false},"8.1.3":{"name":"micro-kit-atlas","version":"8.1.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"~3.1.1","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"800d066c5cc2413f50b5c55d313b3c223d1a131f","_id":"micro-kit-atlas@8.1.3","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-4sEOHsYvbaQtz0nGH38/lKrDZdTRvN3C0io7yWtRYmBq2YJjJ50wrA0e4OzYfCMr4S97B/Wi5Bz2dfnm2Ki7wA==","shasum":"8193659b03c7a4dc88e337655354aab48e320112","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.1.3.tgz","fileCount":63,"unpackedSize":147778,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcd+mWCRA9TVsSAnZWagAAmAQP/1ACXpfel+6wZ61w+8C1\nj9JPO85v/Hs++dQRNG3mNZYmJYJ5Spx7nDI2ewsGtYR/7hvzQPB3A/evODBj\nTSqWpyooCvrx4XdZ6A5RnrmaQdb3PFxjfQZ42onI/5nexXDojfJeSGZz8oMw\nwKGyfsXs2SgBC1dq2VdbVtQQwMi41gKeXthJquqrjT2lXucL2B4XD/eYhpjt\ngRkPA3Hlp0Xu8Ml/xbccyqdVjIgjVxBYc9Wqt9q5I6XFH48y0TEAZTs6+G+C\ns43IIZxJRpIgvMfTFMUNlbjSIh2WeL9Bc6v4Sg/NEAYZNjqoXe43OPcKIZl+\narRO8Qookdxx/+ZJ0tHAivCgAgQzUKju4pJ99bwcERAJCnABJUewm+I25LnM\ngFum4tyh+9SqdPYT90Dqdq7m4GVNMSBTTz8vJ4nDAugwuw52dJ+YtE/g+04b\nts+GdyTHR1o2tLFYg7RcGCWkoQeu8kFO2zvDk5C6ISp9UEsjCrzTWlPeusaY\nwdkl6nb3tdjjnE0K1r31WHHdYvheImIjWvdmjIPQAOWXhUH4G5Bd2OWFFNFo\nSUNR03uOHkw5/yPugcxfWaEqOb/5qsSE+JTk9WOQ71+7z4S3Rmp//Mi9T187\nA8YlIXbOwQ7/sm08J73nakJeI09kiZDTJwBeP879rgjNN+Ikkj8wIxCx05w8\nRKAH\r\n=nofX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFDlhj/mOguKvXx/8cYuUox3MfaB3ct6HxeOWU7Eh1A4AiAbxSXpRX4HNrQKxeZOTLMjl0IjGXj8z5rfeRqPQ5i41g=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.1.3_1551362453411_0.88859588326953"},"_hasShrinkwrap":false},"8.1.4":{"name":"micro-kit-atlas","version":"8.1.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"~3.1.1","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"2f5f0f40cd60dc4c4167915a2a901e7190e5c23b","_id":"micro-kit-atlas@8.1.4","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-Wi5aW2KnQPctwaZsAwTeVz7un7/Aw9KFjdchCJJQ5u6L4k/i047JOBOZ1mf5+leFG9n8up1Mh4kAdptRL2+1+A==","shasum":"c177f6a8305fbc1f0831702699d0d84649d1eda8","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.1.4.tgz","fileCount":60,"unpackedSize":148184,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdFIQQCRA9TVsSAnZWagAAPN4P/3ZCIeBxdy5ydlOmnQXO\nbqWbrLJGnQpUVK1D1+Jbzhe1gYYtuzF0v4VIIGK2RkihbOBEptWPhfR11q6w\nqjPwXuZCZmzH1Hlgwqo1cRahhChonm9C7dwZvNWnECESgyobJ8M/FsfBIeJu\nAGjQBfllbIzgUmLPVWS4er+p9Sm/WTYrDdgkGXjKP7OqvM5Sw50w0J21J6rD\n9Sb3FgRvAH0zC5ObxNVehp7s7U7g4oxcVKemFgL0QBpIirMIlrawXE+DXGYG\nQcmg3DqjB4ka1EVsx0nDcHLIZKKtnT97y4DuivdiyVKij+JiGI/hgpzy5z7a\nddjfqk4H7eo0Wqrx3KBQbGeQCn+BB0kypasn2xa9XzOYvltzDBTJVPbFheaw\nw4Qp1eE1wJBUv8di41owdKp4fiemVpqKyC0RCKVKrvYBOvTi3ynMhNHG216V\n26yzXBtfYH7bJ+QJ4hCQ4io43y9K7cX5+jXAMNF4cC30Gg6g+H//V8cY7yKQ\nSZD7ufBdcuW+lntiPw4cerBkvV1Zi4wQUn7id5sfsJ+CQcT0ZWxGFUAyeCH0\nT2EjhyzL/1X1UKQSB+lU6HeL6ehiiPhAkTAQRieu1Luso97NJx3yqT7z1sAE\nGZrzubDYrRogGUCKhGp6qHrYqx+1fR2P66RgEeJ4Gdofvq0ye0K54oXNGGLM\nRw1s\r\n=MZTC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCCzjLGqxQ8rnlhnmKZJgzazawpyAdnQ3bWTGORj2u84AIgB9msTE1lEbNh6pQhOHlUA4+syDRrkM/UViIXs9HILnI="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.1.4_1561625616022_0.17389767877946083"},"_hasShrinkwrap":false},"8.1.5":{"name":"micro-kit-atlas","version":"8.1.5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.6.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/dd-trace":"^0.6.1","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.6.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"~3.1.1","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"5759f1c482987d2a6adfeb57823073e0de72a319","_id":"micro-kit-atlas@8.1.5","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-N2S9za09gsRT3qdRkwNb6fGss2nSnJYYWHP7Q9XNHp6nqXP6KleZput7tDFBPkbQV1E5vmUzfy/OtGFTvcHGdg==","shasum":"3eae5e446dea2d59870222ddb3e39bfdc9364827","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.1.5.tgz","fileCount":60,"unpackedSize":148183,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdFLvCCRA9TVsSAnZWagAAfKgP/j0WxBQZJ06zcO0bejqH\nPcMT07Kau0PupdiNZkRkjvOo6llEgURwCPF/kfJUFs1fQBj1vNJkLB4ycj9L\nd9djOFWWSUr+xsKFirBr3BA9VSzZkYEn3dnRPMlK7G7ktFsv+DiBYm78nCGV\nQCX0By8tlCo9y2YVINJYw7cwM0afUurd1/pO4wHFAAZpC1XjJPqGiaslE0co\nWgLA+7nT57jjZ5FJuU3oi2oUecWbv1vsCbe3rQFsah5YvIztXiVGxcoZ4XcU\n0l/2NBDzV64qhksK56r5HRLEkJSD3tFdZMAAOgtpL5ZwfdOEI2s/S0Is1EnN\n9lOuPKfh3/iGpSfMBiZMmF7GKsKzxIqX6GMER4JPTcS3WCFdf0cTdn86RHFX\n5+EqXxjT/eFsVLTiDIKBBImT8flO0CGsbu3GgOBqlRPG7Y/3mmtDM2YKMJ1R\naZJYJQiWmxY+x8hLIF+2MVuABr0LiRbpBxwgOPsqjiASNWt0lsE/sP/OmBdp\nEiNq4NUuY3LXVb9rMUBAzHp+pF56K3Xio4qpC2NfAJCZg/3YNPLp1D+2L4Un\nbuuYz7PJ2pm9s+tt+gQ3PDwbaOzojMyr/ejmOgPc0xWunfHw2au8ca5cU3Dc\nTEBypS9q0gQyYX4hE9BkwpOis2C23Y2UbFrhyaKjOp5asLWsj4SxkcH3pnJB\njUfB\r\n=TBJ7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICvQn5z5JU5+HJ2eNzba9PwFU10b7gA9iH4Hc9BRlqiQAiEAlYoU+hqtxmoN7fomQZgfU6b9uJlpnMbIZKf78o9j5QE="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.1.5_1561639874066_0.40132206874008425"},"_hasShrinkwrap":false},"9.0.0-alpha-1":{"name":"micro-kit-atlas","version":"9.0.0-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/chai-as-promised":"^7.1.0","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.13","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.6.8","@types/proxyquire":"^1.3.28","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.2","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-shallow-deep-equal":"^1.4.6","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.1","rimraf":"^2.6.1","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.502.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.9.1","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.13.1","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^6.3.0","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"c2e36655fa274843a25a7beb87f11bafe9b9bbf0","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.0.0-alpha-1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-+ebk1HdQsaajSqJSbA0Xff1Ie43tApn6hPS81iaP3pG83dtfB+AUt+f7/VWuW/5pFeIZTod1i43SQcEDy1HaLg==","shasum":"87d64df50f2eacf5b7045587d7a48f46184b92b0","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.0.0-alpha-1.tgz","fileCount":9,"unpackedSize":28253,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdQq7TCRA9TVsSAnZWagAATXoP/iLjxHWsgI+34KJ4rIy6\nJsbrl3toCmMBURDchpIlyMl6+kTpEEKUhZyQCST7uiP246zlCy5J2tNQGu34\nIUbP8wHoDvjAW3yRWie/Amk7shIMogOxtzvFGlQZrWj+yFEWEnZVRzxxtxCM\nR2OmGU//rt0SUqOb7V0KfOcYuY/rh8KPmwbwBzXr0l3qcZUIKJAwFvR4sX9v\nmXiY9z4cR0QuOLLi0L+FWRA/XVsXerWImfKfkuXz187I6hlLLRYn2AxBx/08\n+Xp9llr3UaNzi/cy7dfyoZNy7A2NKbpWep6ZZ4WBvBC0mtGfo/Mnd0A+hOli\n1oN49/djY7ncNPeHYrcbldbGbYaXYShZpVHc7++HhFg2h/lcVaDd6/YzG4X7\n8VgPv9ogY5ohVc2esR87VfgcRapMX5M+YSFuMW8uvYs+jM0X+ehh/W1gomK3\nDAbaTfah1K/866sI6L0mA59BT9jU048HeUrVCAgWLscr3rvW7YfqTXdYWEK/\nP1Osuo+8fC2jioSlwtj8y+kesPaTngugNEVit5rzFfu0fw4arL0qn5RHTsM3\nkYl4jgeKXIceAcMZs90wqtzHrIZkjBve+GfqA8ClJ9EzY5Es9buXAigbTcXi\nv/d24s98IJ6qF6xEDikF14zLIfr0+AaZLs3RMCiEOG7D66uz3faJiyY96ygG\nmdJW\r\n=hajY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDW/SAMQZryWssNPJQTbk/liG/XGqjvyru6YcVNUZnYBQIhAOFyG1hfiftCnlT2KYA52Po3LtCEj1J6RyOfvJ+kIqxo"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.0.0-alpha-1_1564651218752_0.35769892129333414"},"_hasShrinkwrap":false},"9.0.0-alpha-2":{"name":"micro-kit-atlas","version":"9.0.0-alpha-2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/chai-as-promised":"^7.1.0","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.13","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.6.8","@types/proxyquire":"^1.3.28","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.2","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-shallow-deep-equal":"^1.4.6","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.1","rimraf":"^2.6.1","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.502.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.9.1","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.13.1","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"14f83cc45c63afb2ae4dd4716867f8c9087c369d","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.0.0-alpha-2","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-2cbIuY3T/ca+Ewqx50zO6hXk+Z7TliQCZe62qi6zkMWEGIPrUwtEMQTQbPlCTVfEXHyJF0NkzkbAy6VHELKd4g==","shasum":"526c2f4c26f2748ddcb03c5d6958c2e0e2da5065","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.0.0-alpha-2.tgz","fileCount":9,"unpackedSize":28253,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdQ+AECRA9TVsSAnZWagAAq8QP/0t3qI8tlotos99bFDUE\ndULpDDLGntx0tGSrwaDI1iGgp46DgO1qL7fLUNMlPxXt7+vNH84UbAggqhWT\nPrUx1vufCY5tCemxInJDhrmyO3qu6+wrBVnYaxEKIPfyPk+pnEUoL1abSpST\ne9oxF07hLlfl0C4kexImekQNoeC2FpFMN3qrdScLLEHomz3cIjIo6AhQW7h8\nTaA+3O0REMXdMn1l+rTp4grzHd+BjCdcMOzgZnXavAz3eer9LL6hGORMRqsY\nMZQukLsxFqdxA6WUZIg2Ne9spFZRoIY5i/xVhX9vlB17qOYiHNMkTs/zVGBw\nQx4UqnIzDzWAvzcH/MWWRVPvJk8rFZCFLwKxjYckK5+JdDCXQ26zqhXh2f0T\n1I4X9Xzp4sN+y0/qbXZ7mF0wPCUHSZPUPHwcllEp3WsrYfCG4WP5IYNvJ5p2\nFSfLZmywZoxKs1UodA9JCp24vcipbXwHW3YOCs+MlFPE/dE7mfau/cIViJ9l\nMvYjufnDpi5E+pCH/z6FqazbdCp7QfxZKjaj0sKOh5IfaJyY3E17Y5klsmwe\nNUW8473yDcOeZKtD+SDbCbN9w4Zk7D1Vzk5zrBJHddhAAM3E/BebGmwraSuO\nAC+H7UzB6c8b0wIa5FRgnTARwOmxpmSXSIcArgzP0yj/rs/8vmkSBWiQTRbU\nYaHb\r\n=huZk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCp/OVNbxHBFv+Jua4iYnu91YXD2Jn2YcuWcFl6/NG2AgIhAIKrmPhMcTAV/ioiIoxg6N26FiNf5Hb/PsheIIDLmKsM"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.0.0-alpha-2_1564729347766_0.46007326941234994"},"_hasShrinkwrap":false},"9.0.0-alpha-3":{"name":"micro-kit-atlas","version":"9.0.0-alpha-3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/chai-as-promised":"^7.1.0","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.13","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.6.8","@types/proxyquire":"^1.3.28","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.2","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-shallow-deep-equal":"^1.4.6","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.1","rimraf":"^2.6.1","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.502.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.9.1","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.13.1","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"ee5cb5226a9a1f94d411368102e1d5812f7b11d0","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.0.0-alpha-3","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-WJmCf5RUb6oj3wkmmPqbySq7inxQsPRSl0e2by4GasbOl6+o5IFgRZ5Y5kVx1Mtu5aLx9PiQwCV25gm7zd0nsQ==","shasum":"e3a551ded71abae0da4986583ecd2bb2bf563975","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.0.0-alpha-3.tgz","fileCount":71,"unpackedSize":187837,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdQ+6aCRA9TVsSAnZWagAAS04P/09AKKe4B4940a2hU5pR\nS61TBXJPplZyVIF46VRSiH7qHw9HRtijuRhnzrYiju+z6UUY+wCFwOJvy2+a\nayJjFUvgJ2z7t96FXgqWm/leYulH7aYxlkl0po1wEyax2eAyAV8vR3DVVNl/\nJb4QcBfaW4mZCtcHrwIfzpzLC5gSjXgsqo69YNGKF2lxBEOZZxjoNYAhapuo\n5waj/HQ1a8eJ4+N87VXZnz8EMqZjfDYVtQ2XKvXaXzVrEWxoa8V1qUmOyOqc\n4wnjJu9HNx2NCpDiAi/DaHAhSYUymlAm+k7XdolitTwQx7A4Li5xD2wlnKSH\nbn/1WI8Iswt9nqfP9gvPV3hWT1qYxJ93rYnZsvhR13M8px5pC4bwRk1hGlNP\nM7XvazQBOCXw/eNyo5LIn8uOODnHKgUfxnXVzz9GwdS9vRTpR6kPWDOv2dLN\nF47qASgPISNP243amxnJiFJkNJwwSvgBcyQy0ZdqHwUKoRkp5fAwaaxdkMQE\nx/tPzshpZ0CS1Wihq4k8olSmUnvabIUe7FqX0db+f00AJzF520+ZzyTOpqn4\nClvmWUvEseRStkmjfYq2pK49nsK+zs53VcBjRwqXOggnXFsMPnC60NC6HYId\n4zIZ1Moveq7M4xOZ67mpRYmix7GgXn+9/bSjPASTZ+vjjiTU5v2uIm/ntO8K\nvz9u\r\n=UxF2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGzU9PKlTAe0UAJExWHQa5MxM4gtKvM44xKsXAcXraGSAiEAvOSQ29xXwNckYEAk1CDk3Wp0h0UJUyU1yt8BZ+B/Uvk="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.0.0-alpha-3_1564733082259_0.20442256756766097"},"_hasShrinkwrap":false},"9.0.0-alpha-4":{"name":"micro-kit-atlas","version":"9.0.0-alpha-4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/chai-as-promised":"^7.1.0","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.13","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.6.8","@types/proxyquire":"^1.3.28","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.2","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-shallow-deep-equal":"^1.4.6","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.1","rimraf":"^2.6.1","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.502.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.9.1","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.13.1","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"2e57cc30ce1b103764e181754931a37f878e3db7","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.0.0-alpha-4","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-Pia4vYQ/QP/BdgaQOiVSCtynjWOVVnHfYrlqEI2A4O+geMX5qPuAJsddDE2NMwHGTN73VjnLiYyCf+coTVttmw==","shasum":"162eab8d1f2235564fc8e1c68a83c18c64168884","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.0.0-alpha-4.tgz","fileCount":74,"unpackedSize":190788,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdSTOSCRA9TVsSAnZWagAAXXIP/0ueQ19QMaaTNYw6Dqj4\nCMbSk0lNbPmJsK9hsN6FFGV6R5FGnVaZhN/IUohe64AzmU7zHkxyFdV9VAEE\nMFN6U+v9CbH0Z7Hn1lJ+U+ktksjV53cpoB5yqs2RJJFugTe65dYWkAgpNcbA\nJHKFCTSnr1tHlNE8ZT2DbKlOEOQtxg9XwuxGfjEH6LRrqIIxaC4FhUX7TGoc\njrjTUN3AjIayKLIAv7y6LwZ3VowroJDYzz2ktZNFmjEU77WUxjBaa1O4Smpy\ngVUEjkJ6QwLEDskvg2nf6wNgM3JhqsmS+Kv9iAhX0UCly2A1zrxfZwT2TK/5\ncFAk/QHZ7SCpvLSGYsFmWs+zVBdT1/hYSr0ZoSK7CJbGg1q3el2bAFOrLd1J\nlv4lXKjSCKNQHdfDSWyeqkP/yxGI7JwtMqmKCLoowpHWyMIakKW3MmvuakSl\njpDFjN0b6YxKdRK/EpMKuW8jzqU08pq85cuqj4lf90+Jj+WhTDSokokgtK/0\nLpad2jBdgfC52Jg5dqivLa4F1J0oRFkgIg52PkLWYsXNhqhXn2lpX2TRdQnK\nIRa72o7xxpwOV8t0WKmug0NK8mmEuj/LUivFOgDAQomnWN7s7uANMWQzC5QG\nFpsaFRrfyeS+XMxbSzeKfSHgvJLHx8zPeNbhqN5iTQrKX/8odo8YHNSEBh5x\nReHU\r\n=e+LR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDXEnsNmDUi3yUGIkmiOFicO6m8+t/wLK1M+0YWTj0x5wIhAPfQXuILRZa0xxK+Sr5bjHgYG1oDCes4REilUpV6nhcU"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.0.0-alpha-4_1565078417461_0.22511977616624823"},"_hasShrinkwrap":false},"9.0.0-alpha-5":{"name":"micro-kit-atlas","version":"9.0.0-alpha-5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/chai-as-promised":"^7.1.0","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.13","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.6.8","@types/proxyquire":"^1.3.28","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.2","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-shallow-deep-equal":"^1.4.6","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.1","rimraf":"^2.6.1","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.502.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.9.1","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.13.1","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"6be8a5b92d546cbc112ddb19bdd5113f5a1d3d6a","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.0.0-alpha-5","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-QQOvdgcK/Ucs9macmc4w+WLrnxrFI5VBBS2AyQtBihHKGDheznDBWe9zc8YkN6t73r5Q4q9KdmBF++eObZS/pA==","shasum":"191c50caf4b455c58f0828f9516310525f3b1270","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.0.0-alpha-5.tgz","fileCount":74,"unpackedSize":192506,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdSZXMCRA9TVsSAnZWagAAFBUP/2DMoV1GQypDT0IspUUh\n9CZOrAyhTK62NK4ZbaH2vrhyvFqhmYjaezFQm+LwtHnO027v9CvauKMYETwx\nPi1LdLpaIoMPr6v9Hy7uD+veJB8UkiyhYqGk66rE/t8/vUIYYkZAqHaJ3zvL\nbX9J6Yc+J9xOM1M1rvEvu/z3zQyN4fSlMdYm5MUju2gbTVyPrz4IZL7uOPlB\nYjFjXWLGqPcHu/+k6w3NwEG0SZVlaYnRptS0XQlKa0eOJoIyZ3vrXYcobktX\nqcYJuVWfW/Oup8ZYhElrtS0Ksq6oA8C+4ONAjwOC7ufSdqZy6CMG2xCitgly\nMbI6EUV81iSsYKBMQfV2+rnDvyeb0D832zLdQOgnUNUdWYLwRsJeQ/tyCwE3\nTmgLE9q9CZfnzp7PvqomU/PQmN67Boj+PpRwTz1/434yp8Wvm9zl0KBFokpb\nBysxLoA1p04RSBhO7ebIZp1wb+QUGidT0+1Xb7B/2rzVyB6IclzEuXXtNtXb\nV3Lbw650aBgOaeMUQaRG/XqBTcy66z/iFx65dY6rfOfUb/bJxrjgmYEUf6nS\nNvvS/MfBkUkPZ/JmVsUmcX4RcmqtnGNCntsbxA/ESbgs2/YfnUpsZ4EEPCej\nknogB2fzVicWjenJqpt7uDzrDb6YyozVQCrTW5AqgmANMl1kKMmrt0T8ZXNM\nCMpg\r\n=j+5C\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAsSfbBzCOPvOUNk1d2Rk3a1DlzfO9zK25BCw0vCx7iyAiEAzAQ5VjMfTnRPmIPVVJ0Qjai3j+pXojgswLN264f6mfI="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.0.0-alpha-5_1565103563640_0.00550007525789753"},"_hasShrinkwrap":false},"9.0.0-alpha-6":{"name":"micro-kit-atlas","version":"9.0.0-alpha-6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/chai-as-promised":"^7.1.0","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.13","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.6.8","@types/proxyquire":"^1.3.28","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.2","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-shallow-deep-equal":"^1.4.6","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.1","rimraf":"^2.6.1","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.502.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.9.1","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.13.1","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"3e271dfd2d58923e327b1c768fc12701a6b8c847","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.0.0-alpha-6","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-LGXpDCiW/YEwjVySwvvYkc5nE4AXhPJp1z7kv7vo5YVAy8pbgjHPfr3jxTgofnWrND6tWiVLoIcLPvd9uBNdbg==","shasum":"5a6f747aea9e29a3d781b8fbbc23f8f2222089f7","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.0.0-alpha-6.tgz","fileCount":74,"unpackedSize":192455,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdSZs1CRA9TVsSAnZWagAAklgQAJeil1pENybX/jY+WiuC\nJ4W3lhrdbOVf7mhiVmZqwMYNTMK1qSXRw8rp3kFY8bcqajECOyJAdUmcPN27\n4MbMM95c35vY3qt2BN31kzgsY3YfIghGa+kox6dAjDaIA1SfaePYoWKZeVCs\n3mbH7V5AFBqbMhy/kwqF97nN6QvEwE1mbOa+lnU8WuFH6VagaeRiH1XgyBkV\nBa3l4kTYI1Nm2fmELAmYWYMZSlufW7lUMbBkqwoI50M91O5DlI0sagF3q7R+\nX4qVPCUz3bykbaDZMbQ9CkFh39PHBBbLIPafkMethJIyj/oKpTGVCXiCXhmO\n8kwTp1dwdAkSMo6BWh8yRnRAn7dhcM7GoKaxtuWw+iQqLpZInrOtSy1gbvmh\nQwub51K7Qwivgb1MreY5KpTT1s2GK/jnORtlD94mZlNWwLTgvseHaqYduOj0\ndNoOj1E/8XMEw7SwT7mOWx0RTeU5u+aEK9dH2WG7m431Z23cVMIQyYTvIKt+\nWkWBQ/rvnKFO5uzx+DKx5XkF8Bwn8mUtzhstwpolbVMM+53N4rptlysChfrE\nbxrCEkuVjM+dN6AVtzYZcdEBWniMvpqy2NvF0D1APTNR2PxkD/ikaRQGubR0\nWyyx4XBXOWyoGpYWQ01g/hkZHsWnNmzEM6aZKjXFxx4r49a1nWQh6Th9RfSd\ngEgp\r\n=Y31i\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBzXBQD8fiQkl78TOWcghMV6pcSONjGdcNY6C4eMbuLuAiB7VtLtCFIAxxU4uGWPt9ey+oJ2kZ6fBb9V41w9XJ0C6Q=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.0.0-alpha-6_1565104948590_0.7466616647877216"},"_hasShrinkwrap":false},"9.0.0-alpha-7":{"name":"micro-kit-atlas","version":"9.0.0-alpha-7","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/chai-as-promised":"^7.1.0","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.13","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.6.8","@types/proxyquire":"^1.3.28","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.2","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-shallow-deep-equal":"^1.4.6","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.1","rimraf":"^2.6.1","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.502.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.9.1","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.13.1","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"531ce1204cd2347abbe9700c8cd938f7d9bf3f0f","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.0.0-alpha-7","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-5rFmZhEMKSUFSBC2gOYXT6CmbUxLDysRTRceaZJblHDNnXaqZNHOiX85HkkKa2Aw0reqPd4KTl84GDQ2WYRVNg==","shasum":"0887af72f20d8a235a67b2025ab8fd6351d3129b","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.0.0-alpha-7.tgz","fileCount":74,"unpackedSize":192509,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdSni2CRA9TVsSAnZWagAABfEP/jDYP4k6LIcLdflFAZE1\n6pvZM9BjOLLre01FlN1YHL++JD9tSsq+1xR5wGs6t6iScs8U7fPwNRHOKRgs\nh8UqvgWsNwR8Syc232IZg6SNz7Unw4WPVjfnREqteDZCiFd5h78y6lzrxqZR\nRHxR6N4oBQz6PT7csEPacL/AV7+FgToRpVN4n0wMrv/iJ2luAMzTTWOmpzU6\najqMEnsUmTXphDh3240+mYeCuOiBHxsmeuHB29zk3QVRm0WR7Ge3HhERpjyW\n/R+f54+G1SbAyYJr4+ZU7RU3edG3nTHwtOiMRsUcZumQ0B4vD7Icjsmvkq4t\nXPBP7+ho72LjIFnn4XjzS/MVEzLotHtnQlzNGX+8zdbefovWW8NyBQkGlavj\nTEfMxgr6gaFcfkJO6Uwk5Y7OpLekrPAYykIMl8uKlyVhoX1dJK3PaD8/0uob\nPnHcUy+KbNgasvFc/+k/AVNOWiOKivk0HrRkXGpwpsRyxUOb4ZCnsQ0TXSBi\nGuxEixD3ITuE4mYIyoJ/XdVyhydqHsiXKMZTloVDqTiAJvqAaPjfeAcoxieO\nIofLqtiGLGVvEkBDBy8vl3EKA5Y/A0hv3IKlXrzNzsVPNAKJP7pzhOImi+7d\nuKmBTTJLGGxv5/yA0X5kYoqQt3JdwrrAfwNJB21dPHkbrrBAQHwhq/X6xHFy\ndwL7\r\n=S/MD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIElum3EXokXVYwijUAe+W7KvMQ7LTf8Y6spp7lbGyq1OAiAFkmWgsFjUkKMSxk9LXlMh/nIlHeiWCJD/TZvNgz5lcQ=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.0.0-alpha-7_1565161653987_0.5319814691064111"},"_hasShrinkwrap":false},"9.0.0-alpha-8":{"name":"micro-kit-atlas","version":"9.0.0-alpha-8","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/chai-as-promised":"^7.1.0","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.13","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.6.8","@types/proxyquire":"^1.3.28","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.2","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-shallow-deep-equal":"^1.4.6","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.1","rimraf":"^2.6.1","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.502.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.9.1","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.13.1","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"d67c74ebc2e8ef4d0f81128497a4ff39c0a2fbb1","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.0.0-alpha-8","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-/Z3n/ZO80fg1Yy0suVi4rEQQqJMnzpYCO+VZg6GYYGP3upJewX/r6ExYoP0YSeFPgTfDvx29iEsAea721s/daQ==","shasum":"0913e9652ea7238f63292686f34ef49570266b75","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.0.0-alpha-8.tgz","fileCount":74,"unpackedSize":192493,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdSnp+CRA9TVsSAnZWagAAoJkQAIO7HixVh5XHsbM0VVQQ\n0PA96n7vN/gcUSmbh0xkITGzgI2eVBag4Bv5tRtWcRHzNFMNAVF9F5KH4EJB\njFNB7ToW8Y2KnGKNXz/JKiGPJQ5m5/Dp0BVCVxRIVEs2GTC1ZNsr6Sfh4Cnd\nqtGypkYTIbMFjBxvZENFpKD6m31pf1Vg50uplpViM5bS9/4N+GcmvYqG6oS5\nrVzUOXz3cJSIJfHe7VRK2tO73J76nHB2oUPPkaWGnNmJXPf5ex8xf/y9WLov\n/JK3FELzmRgrT9SPeAvG4xL9SGP3iZpvAOZ6DcrjedrwvUZsn7XBsgkgRl9f\njeTcx8n4tWAvpw5/TQ1kQF+e6RO3j+1GqqWqRV081PNzyp3oopF6eu4bX6Za\nHLu0TFFq3WwPW8dgt/kB4Y7K4o8RtwGVOsusMeOFuH0stdjx6nI2hTm54pgr\n9LJ1TrUp8vcSmqGdPFm/NONwsPXVyhwafpOvokK8ywfftBhKiPkRbG8EHCTE\nH/sy47NzFk4mtLsYCQ1cFCxgS73XT7wukkTe6tIwXSO1AYeSv0LDgB8qrCI6\nXkfY8F6giKXZGWwh8pJtJ4m0+SPia1PpOshePLG1qOWe+OBUHH+cD15RpbRY\n1cY3DRTNDCqrp7fXUw/YsFHjAbJbKhvKHkWraWItdmGMs9+cKH0WIso61koC\n4/y8\r\n=DmDW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD7vTcZNOTYFhXTka9fr37ccsfv+rpdIl3V9LbWoLeadAIhALbv0dDmhjUrWi7LXytMSbWtK8c+3uZIt7Ol5AsdvDn2"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.0.0-alpha-8_1565162110132_0.5400729495874184"},"_hasShrinkwrap":false},"9.0.0-alpha-9":{"name":"micro-kit-atlas","version":"9.0.0-alpha-9","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/chai-as-promised":"^7.1.0","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.13","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.6.8","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.2","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-shallow-deep-equal":"^1.4.6","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.1","rimraf":"^2.6.1","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.502.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.9.1","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.13.1","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","qs":"^6.7.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"4cabbd35d8f655265704dc31e3d3069fd64d2c34","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.0.0-alpha-9","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-rNwCCqSvwDmywRue/Z8frOfUJMeL9voZ8u5+wf0FhhudfyT0OnAyz5LYy8bHdDdBtCRpgrH+wwEYY7CwhJSYbg==","shasum":"1e61ad442f684a58d413750477eb0233d2afc4e7","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.0.0-alpha-9.tgz","fileCount":74,"unpackedSize":192410,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdSteSCRA9TVsSAnZWagAAkA0QAIkk2oUj8w50l77lWazf\n1O4DbMUnagOJA/Yy24brmX5PcqRgtR00pGoX3wE7sTxkmV2Hr0o5h6VC742d\n6m/0BSAtW9MoJdsBJL7Y4luq+XxkSsj5T3TO8c5JdzQQ+QK+1/WZrjehwDdy\nErFcHPtR7V5mNq/ohHhQU4FCuuLp5+kUF2TGP9gpzXfmhaADD20DXIVUGD2j\nqzAc7q8qQgkDWappW33RC+RtD9aaBN8tzddI4NX4Kv7wljoROq/QPXgJO4gq\n1U1xP4EpQtKQiOU/5Mih4oQ3xJQj3zhNLP1clqoRxjIvXT15TN1XoYTZ3Djh\nShPRvLmEPz4GMgZ+9u0HXRQHGp/9c25/qCjA448/QtDID8C4uRPJCuLEUuDV\nUipVU6drbdY6KPO9yW8pzl8Pj/5z9SbgOqKyxWEZ2XQDuOfyeKiuaxEBpXQd\njryhxS8OzFCy19mBZGT89kUHlkz8RSZyUu0zfLFWujJpIQ37GZp0aGll/uwe\n44ufif8F23mdo2lhffp4zSsLKi0LicXUzQsFLcvp29FLmiE7kjUIU5SYzj4V\nHZxnU3j6fn/PYTLgJjHFaUIyjLD1ECgstqTVPwJJrDS6kUSwsGl8Vzdb4ra8\nf/ujZSqs/2stXjtVueAyzumQdHeOelIwIWELiNce98ruJ7Kedfi6XpqOGF9N\nTauq\r\n=HGz+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFtqt4twXnf+z4BEJhg5yml1CGWOx9Vn+Rvkk+zSF7mDAiEAj0/yHlEiH+EJ8jgAFSLiENYh9FA4EGe+VfH/qmPUBLI="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.0.0-alpha-9_1565185937965_0.320405341337348"},"_hasShrinkwrap":false},"9.0.0":{"name":"micro-kit-atlas","version":"9.0.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/chai-as-promised":"^7.1.0","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.13","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.6.8","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.2","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-shallow-deep-equal":"^1.4.6","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.1","rimraf":"^2.6.1","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.502.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.9.1","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"f190a4ad54a1ad91c3c40b6247aa598a9c8c2ff8","_id":"micro-kit-atlas@9.0.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-MS89ZaLz0POxsdOuVrjCQqA8QBLJ5EKjpI2X2B+tVCCYqPF4XyBrO9RShtFYgr6+A4p3AvWA7QAtIST5kfQCuQ==","shasum":"098cbda215269204b846aacea05d6a4aec328fe5","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.0.0.tgz","fileCount":81,"unpackedSize":202514,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdTCBSCRA9TVsSAnZWagAA814QAJHRHZB9q9X8zMPJzdHO\nfnsGpq583d3zV5QVj4yF8im0nbYD7zGzWsSQOxx27rqePJ2hOTbx7PrbJwGT\nuMe2RdF4i4j0a7fLln6Pv72Vc0f685S/PqCcblOFWIskPb1jvvsQDqEzioeg\nFERdrjzS3PDO3kQNWl4YfPpszz0uh3H/6iksmZx6Qiuqdb5uO6JCmP/rFFEW\nAM1VZhVhTNpv2jKJnuXfTUA+oO6zAOQQKwx8R9GIxkkcgVzWwpcHeIzr8vJQ\nLvxoBZYYJDMO/DzefEEDYrfmwEKKL017OdXsTlxHpLoTHZJSdyrXhCKJEbZr\njcinDrcJz2ItZalFCbGTTk6xxNMoPBMP2NqhvF9ByNArAdSIpeIZzuKcRwsJ\n3icPq13SsUD/ZPRxdwMzWbJ2590dTC/PGxa3hXo087HxPOrTzzROR8Xr7H79\nNlAvkNJmUyj013j4VZ2+Qjv3N0JLZRVUE/w76tBoNvUywYxoN6piGtW/sxR8\nKPdBSzzc0ziWXhwzjow49LPBJ/rZKNlHYf4dIbiH5BH41pMVXxs+sD4nbjaW\nN97c9WkFK5/gQ6Xq2ZgFqB4fkKgRKtZD4N4D10t5JWkIshCTION6gHpZ2Tie\nUj4xNaS9XoEEBJTJ7C5advasbBhki3I4713TquVmD9fwbLuZv7jeXDcFUty8\nOqj+\r\n=WTPK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCy88EqPfGjQYjnZp9biEcaI2T46sq1VPCMMpK7gjBSOQIhAMq3w5TODt2CqVex+0IQIz0VPYbzwNzc8yYe/bOUEbtv"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.0.0_1565270098149_0.07741150636285354"},"_hasShrinkwrap":false},"9.0.1":{"name":"micro-kit-atlas","version":"9.0.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.0.10","@types/chai-as-promised":"^7.1.0","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.13","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.6.8","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.2","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-shallow-deep-equal":"^1.4.6","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.1","rimraf":"^2.6.1","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.502.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.9.1","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"44cbdf78d0e945955ee7a13adec819f78e3188e0","_id":"micro-kit-atlas@9.0.1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-F8EKyIVUBfFjX96CMqG+z+YHPwTVq7qohZ/+iL+WloEeHdowpmspFhMSUh4TeFl/Yl2wIBLpGDk75Li+nNBuZg==","shasum":"6a490c8466c6fde70bb8022b2ebf5c116d337dfe","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.0.1.tgz","fileCount":81,"unpackedSize":202246,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdTEE1CRA9TVsSAnZWagAApXUP/02/kf8VWMkFwDa9fjij\n+w55bgOSCN5FZ1lTTUBfhSDnvg+WXp3GFiH+KboTxtIBhRhk+DpyXbTVdzEq\nfCMIDRqUo6lbSwV/BUilSOpe/l/0tyq/KuvOvP2WDvKPFVLNQSJJwjePiqGH\nfEVgwpYvpIf2KzY452vevShbuRE5OuF5idQL/xdA4LSCsh3OKv+mWooqmyFy\nomrgnMNIZGXJ23HMNZpTboceLpWbjqncfLv6XbgDNBaj3Yg20AvUoT8qNcon\naTlgn4CtEGC9hbW4gSnT3Nyz5PWzH1p0Jb0avBfgDzLPaNdjOwFdsDlYooj+\nKXUL42DVrPF1ZUERoyD83eXyY2Uwst70FdGmiZ2Q6r7oeYBHBnLsTOX+meRG\nw6WIcOJcOi5fNXkRnzGp43YbQm8OGzG7/S5iAYyJnVCZG27XYroOQXf8u5c/\nO6Vt4fkW4OQC5k4qe/6coJL7H/0+ur8abIGLPVwEDDs0LJ8Q6YnvrXLJI8i7\nDYV8lA8s+MB4tVSNWdQgYvJzGo25DwMHVIg4jbkp1YZJql25+PljwBxkRazk\n+EVovFPcwvCkKUraAa3FToadOaWvepL8JZbO9eb7heNSSLJp9vQd6M5aPGS+\nTwEa2L7dSDdVqxy89t73SOLtfbcgNFbcs80XZ6b60b21Eb1IRtpKKaVwSTVB\nlKYX\r\n=Ji5l\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDkc9zQrLUmcCrzji8U1GwkZ8IT+R6eHjD5tTWQEJ/LJQIgTk8FlaxfnkNdQHgDnP2R+D1ApaH/QkNsVi/4dhnOlsE="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.0.1_1565278517097_0.38126922379955364"},"_hasShrinkwrap":false},"9.1.0-alpha-1":{"name":"micro-kit-atlas","version":"9.1.0-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","build:lib":"tsc --declaration -p tsconfig-build.json","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"764cea0b516c25e55b10468fe8682553993effdf","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Required.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Required.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nObfuscator\n-------------\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.1.0-alpha-1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-B9wdQKoBzkW3543AfouB8YuzbmhUPB7JHhQBTKoeWk4rd3jj/KbQ8eKUClSAH4rFz2o720JWhlqe65KxQhkUsw==","shasum":"6b207fe28685c8269371b74195ce17371c163cf6","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.1.0-alpha-1.tgz","fileCount":103,"unpackedSize":221480,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdXlkNCRA9TVsSAnZWagAAOogP/3RV8JI2RkhPBogOnyT/\n508F+sItkQLSxqj1bs5x7PMcovzwt/PciphSrKmc360cYwlgS9PlRDjTyXW/\n/j9A/Ye9cZkV50kolW4HMSyS/qWcmMKxlKIEjnTCg8TTtc1Q7gFO7vT7H+48\nL5yQWhIeHzVOHH6nKEYWVfd8Ojo55jmi7EZrPr6iN5Otyv2DkRZmsioGxbpb\nVOWxHVWZDF8r4oJUNKH1O+zJ1ziqb615AhgZfy/dfTXyaHuSLV6VOSPVasHc\nwDXWEF0Qn8fG/31G9fFkMAjwzxgyxgUwSvQYwbfwV1EyWrzAoXzcjaDTCrKv\nKS6/LfZD99EAO4UKf7kJBIxzjWaIGhsnQ+bF/Bphr+t4+DwPTt5rJpni1Bau\n4ajACbr1nkDgOhqp9ehwcEbI//9o6QwFUv3rj+uuz2QOKPRZXKauoSuSU5Pb\nOGxqTd790fKXUft2XUIBHlsTw9sj43grfE5Yoa4y6YL3vD6oLe8d3ybFrWJp\nVEMePbH2mB5TCgPxXnPGfGAbmM0RG0pP1MXjy8HgcRpfEf5pozv1H6DsSfh3\n0+dy8E5fovoGXCRs9fSdbaS+ajjC/FaiR9EgE26aWU+dvufF9jJYUfu5ynsa\nNXvZugaI0ngIguYHtLAHf0ZaeC9c9Te+4yX9s5msZadhm9rhRA9sgSzQZFXC\nynTA\r\n=Y4no\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA/hxNm8AW9mm2jb+scDsmeX72m1TNri15aXpa8sSq0ZAiEA3I6CxCNSXSftcEeqFC3k5xdnmYvi8/NboEGG8RPL5dY="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.1.0-alpha-1_1566464269185_0.7626521688915913"},"_hasShrinkwrap":false},"9.1.0-alpha-3":{"name":"micro-kit-atlas","version":"9.1.0-alpha-3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","build:lib":"tsc --declaration -p tsconfig-build.json","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"6e1cfc32ee158d803b1aab3ff655c5286c6b15b6","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Required.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Required.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nObfuscator\n-------------\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.1.0-alpha-3","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-R1zV+szDaeDPlKWZK4Xnl7rAejH5LII4pCUigp0kDAD8Vd7Fz8/ksbjYnk0R3wb1UykS1A4cGuDNV56T/ZkW1g==","shasum":"a2bf11780c4949c6e71b97d33f5f26e597bcb558","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.1.0-alpha-3.tgz","fileCount":103,"unpackedSize":222541,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdXo0SCRA9TVsSAnZWagAAc68P/jonJZVN05J8OMlP9jIV\nITRDSIfZ+5UcCPvVE94nYScxhvM/kXc0jjNuKMvgXbtdIYt2lss3FRVxf6Px\nFU+qwHrp6e4EwPoBHpKCwIlbulVvHvXACb+zwe6Pvv+6AuCVMlQFVH9pG7TM\n4lfnrW2D0AmDvyRcI8ejavM8kpT3+vxRdPMVxtEOgH3iSGxTlE/xdMCHj/l7\nmzbNe9G0/CqsRY1k/cTeehebvTSRgm5yBmjIyOvYyrK2by4YAZAQTENHdznN\nCSt8JM/gubbpR/qh8Ktzk94XN45stleP81uo5bA7Wrl9VxdpAsHSSngEsGya\nyCyVdM/z/erzbGE38xEQQin+E3Q54FH01KccGDajlUQHXCksds45fvLFW72+\nxdbLtHKsF9lZlLmO6tCO4RR54mU1yqlglKdcjBWi/gj57QN4KWcrBDUWlUJt\nDvsU7p1GRmrjYLlYyTfe5dyT81vF5v6fTJnWZP5xq+5RXNGyT6RFoggGBJH/\nLHYD47kG5xNylyp4OMwKoY+Ijo/bFpgkjICN+4RvwPhjRRYDwo0UaPRbJ4WT\nLIWmUZ6gwHi7TuChb50U0tMSW6w5+ohcPB5i2PXprg0CrsxXG1LdSQ+LAt23\nsbdB0SkUpHXtLbxgkIjOwALGEQ+Tt1QMcd2G8KtwPobyfznnwe2+ql6WZ+Cw\np43Q\r\n=lxoy\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC08KTh934QEOXa4IIOc8JkUz0KwZSmwYrdQzXrT6fFDAIgNoY0RUUxh44ii7LCXsmDhffPjqMDE6X3vh1Vcbu/Ecg="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.1.0-alpha-3_1566477585586_0.9728743827697837"},"_hasShrinkwrap":false},"9.1.0-alpha-5":{"name":"micro-kit-atlas","version":"9.1.0-alpha-5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","build:lib":"tsc --declaration -p tsconfig-build.json","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"5dc03a8ddeb6308177431b2a499f4a52c313bbdb","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Required.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Required.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nObfuscator\n-------------\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.1.0-alpha-5","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-cRUlRkY1uyoMHmXPcgAQkvzy1ua3w3Ve2X6DS3R2YBej14OT57+kbXUuzXFnwaB+lF1yqrb9YPqg8eDhuP3c9Q==","shasum":"340470c467af0d50c8bafb11ed894d455aa0d1c8","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.1.0-alpha-5.tgz","fileCount":103,"unpackedSize":223641,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdXqWkCRA9TVsSAnZWagAAaesP/1WP1oyXA//DSCCimJa9\nZcxvxixw89sdlNYGYWuj9B4m45Z49w5w9GdGsWYJyGFg0b3L5tfb99GCVjBQ\nrGOqansyktyAX2dK7xlRSSeiC3yYjopBW8edlhMipQDXFGw3nJ2gAyF4D+VI\nYoz48taX9Wb2cfHgemfVnBXmjd4ws0pKT3VYCpdfewT9wLYNCBJdBtk5n2hy\nzsPMJPf+vWspKjztJlXrQlaEDaJZFJ+CWPYZPN8azdtl3pklSgLBI8vArYW8\nABvw1ks4Qd6imVT7LJxfALoUqAY0IOxlRdozqXgHemVPtZRvYKfzv/ckicJK\nPjPsx5Y/RfaIxt0AvDtqba/8n1dfQS/VyTIqUgicI4j4uKwCZVUKDRxuIlGg\nkUuX9nBG6Xv7Y/vnR15WR9ch1WmHV9z6QZNxZvd/5NQ+y0CTN+DKZhA67MwH\nfwTvt5Se4XvgConBvn1VpZcVlQHlEaJl+xs1y4UHnd4m52JfP2viTOk96bKG\n/857LnT0Q6jBlWV1Gm70iU06Nc+ine+OdoR8EfeULwH82ZfXZqMfmlVRgFlQ\n1tnt+8uJmdXlMduC5CTQKYZ2qkuJhLpFrqLoJ2Z/w92v2yirAa7N4z1jrrwF\nIvc91VC+fEiOup2jbw8ONxb6vdgtW7TFgxULZGBFPrM3fXQmVQFLTNmNG5gb\n9urj\r\n=1ohW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICmZ91q3JhONjFm551ZDPC1xgt9aJaUv11xSwNaXJ3WOAiBh9GzyiayPEsxkuTDZ1ArG8pk4Gxv0qnQwoBmNNBSssg=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.1.0-alpha-5_1566483875620_0.5788601100559816"},"_hasShrinkwrap":false},"9.1.0-alpha-6":{"name":"micro-kit-atlas","version":"9.1.0-alpha-6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","build:lib":"tsc --declaration -p tsconfig-build.json","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"1d4ad1ceeda3e753caaa17c96610b23eba0ff390","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Required.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Required.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nObfuscator\n-------------\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.1.0-alpha-6","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-yOcDb2kcRY+SqdOvD2UfDscxVNlY2xLL79PXhIDpxit73n1NmwSB6hsncpviLE1J8hsxH4dQD2jhPndXfecEuQ==","shasum":"bd835e75250dcd97663603e1b483c5040c5fa1cd","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.1.0-alpha-6.tgz","fileCount":103,"unpackedSize":223654,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdX/oVCRA9TVsSAnZWagAAbKEP/3hJFOSf/SEOWKuwCMbX\ngSclC45S30mzdzuIL3NMyP/viMTR481yxKXug5VRXDNZ5Vs9hLlGRFLZlzXB\n9wulc0fZEhOprWBdU4r2l/1+58Ml8C7DASIZV6mXe4CNX2BmKzlaE9vH3rgD\nHFcPkNGRNN7Bj9j6cbf9uBkn41OUK2Bo7Grq9eV9yux1+jYblrLbIE/vvWTU\nDy0jShQVgmzuCV4csWE9Lzsy5bSvGbCeSPQiURw/tXdbCfcLim2xCR4yJSNp\nE3yxSkSi1qCx/DSZHzFVln26CAR6xRLiGZnX8t/XRRch1rtzZ81QDUFkHVzr\nykyu+Ic+q5LW/8g96+YaUQDiJgM2GKwb7+pf5n4/zMVUVUHhUlkL4Wv/At4J\nIOplMBRpsihJCkjVYKNDpVX4SyBMo4zgYF6u+gSWGMSOcaptQcW5kCMZgilx\nF48AkG/+f4LwuRgWBPdoa99p/exupSI9kmXyoF9IMLIMELH9VxX04/VDM5k4\nG5fnlo5YzYO/5hOpkmOolxB16+r/whnssnlypeF86+NYAvlt6ywyc/vj5ekR\ng+P7naT7afempcWA4btNHd3mG8g1r7XvPtWl/4C1oZixdAPiSN8SqtEedxo3\nqkPBRl0lLAd1P4McfgJJ3S56+oVTCzvW6MzSP2FQPBBDQEwXPAwATfTEMS+5\nU/bc\r\n=RBZz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDSAnyWpBCZBQ6LGrybwhzLQRFnvX3dA9WpJBNnwqo3JwIhAOm3I9BBgNtJorFKQWu/z8e1e9H9H3NL29hmGZZCYVBL"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.1.0-alpha-6_1566571028746_0.8246139363107707"},"_hasShrinkwrap":false},"9.1.0":{"name":"micro-kit-atlas","version":"9.1.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","build:lib":"tsc --declaration -p tsconfig-build.json","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"4ba96aaeb985315ec236120105b3cf45405fc447","_id":"micro-kit-atlas@9.1.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-UjraXUpzVNLtNwcZ99bd03QcGDM/8VtU3B2I/6+j2DotEXd5kEYfZXYKzX2s4WFeP81r4wcvj4d+OT5N+sHZUQ==","shasum":"9d3322b11cf3b6b92bd2718c74de350cfb89ae64","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.1.0.tgz","fileCount":106,"unpackedSize":224819,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdZTQjCRA9TVsSAnZWagAARqUP/0JLps8znqiPwyEnZlvR\nrGVKvDQpsVndSV7pIKD2UWs4A+HJVXS9pqZZPRMFRHpXYv21guT0Am9daIsZ\n1SOZdyryH9WDL4N7c25qJbipqjZfT7os/uXi1HKVSwVok2emXOtgVWJESOlA\na0Qo9niI7HKMWgQfR/XFb4CdPaiXM5DcLEZeo9SuoMHQt0NY5LY3mgIVjgGf\nBp7I+WhG1S4gS0i9PxDMcUZMcrvezG+IrmxF8TgbXhTdeKeZ+clTMYMQNrXm\n7bm5z6sTSQFYL6S27u9lvkpJd5T9fPj4LK0rhUg9wGbR4uCgU9SgChsymdk6\nHHuaqQRufh0VgB3dFWGaYWS2d/brcQmXVHkcZqpkRcwF0eOrdYTAbYhydsjh\nfv5JxlvChevSe6hFNvHmrOwtOiZPooJJ6VYHM9kAbsPuQMha/ZJxBBTxmHGo\nlkeJLbvXg5OiQN+GMrWEbPbrVPIj2wpklqoYJy4LAssiN0ABtTEuM789l/C1\nr2qATX//CNQhtHi5qaW1cAKYbAalZZKLp/BkofnLVzJoVs9TOxVKlymS+6AY\nvao5KGOD7wOEmxRAwJPyJ0lZWQFjsJp6J4NTisWXW0cKuBJJsXmEEoAhpY0c\n+dSG9LaXo0Ilh4PAzrzD+zV61rARHAQL3pLbOY3f7Q/efzmk4Jg6ntR7fQHo\nkZh6\r\n=a8Wq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDvSj70CA9H+LoGCJhcG3Z+/OXSZhX7upoANL+qr8CfqAiBlrUeGRPofMdkkejEQi2IGDFUH0oXsNIFDttt1HGbZqw=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.1.0_1566913570583_0.7181752889666917"},"_hasShrinkwrap":false},"9.1.1-alpha-1":{"name":"micro-kit-atlas","version":"9.1.1-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","build:lib":"tsc --declaration -p tsconfig-build.json","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"08dc675ae497a6d4be94a6e12271d5ee7863e5ca","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Required.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Required.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nObfuscator\n-------------\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.1.1-alpha-1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-6zpvd9wOdKUAQqXXQEjXYMKq/rg4KeBsPwvA0q7av/6+RpwPVnxIi2Qq+fHzM2A9JU7E1jpYls5HbjKvYlEw9Q==","shasum":"ee72e97f47ceb14e57cd3eb6959ef304a5352788","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.1.1-alpha-1.tgz","fileCount":106,"unpackedSize":225121,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdaM3WCRA9TVsSAnZWagAAfKsP+gOCQDHZIqKuFrvtokxi\nqlh6y9u99nbjucYa6elmI7UgHsnFa6+oz/3eLplB3NDjAuPVYjaNGbfKoWzQ\nCDEBTQFed8I3gsW7zir1ysAY8yGopww6stESRyYr6j6oGF9H35eOp55WDdFL\nUCzhavlqxBWm5HtjkB26Hcc2gLhCNekydZJFTNC2cEZkNliYjcHAob5CKsJc\nWxzI1V5tjtZI2m39DF/J4jOrG7XRTqVCVxfZoiv7kubzk2MWD9uQL/dvEAu9\nY48hAxTe/v/6isxLY69a1+WpkzYaM3P0ghbd6KnPNDgK8a5/Tr2jkI1izYH4\ne7fRYWBV1k/BJlAXxdk/O84rnGhHrQra/t6JoLeHPRNvFPqCCa86S1dihiK/\n0/gUkovQjS6tDAW+WIMH2NnTct08UL+047CLyxzwQNyr/fGug3ZpIw+No44g\nz33JcU8I04gIIT2rO9wayR16Q/HyUlXQd+ygF/76OEozyRLhJDUgvnVtuSLB\nsSBY821Knx5e5FR6PF1Yn8nCut1V86+brIq6t8upgScPLOh7WXPTUGBKGm4K\nKNB1It1nVQG0hnpeSOT0l29/ndsXeLA2a5rxPF1vc2LIJZU5xNzuZJy/1ycj\nf7gU5hWaTnWrKSPQdTYZTGKsMIefDiDURLCLIQ51JgpscrKycS37MDg+YEL1\nYiBl\r\n=5T9I\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDk0YHTvMk4RrYzlxs/Ld1l0S2PxVaQTtwGBp48t/wBpAiEAxMHyglJabNLwtxYvJK36AigUU8aLpY3/yYWSx7BYZBA="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.1.1-alpha-1_1567149526117_0.8396837959066128"},"_hasShrinkwrap":false},"9.1.1":{"name":"micro-kit-atlas","version":"9.1.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","build:lib":"tsc --declaration -p tsconfig-build.json","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"d48dab790efa775a2f8c1938624b1cb35a5aee4a","_id":"micro-kit-atlas@9.1.1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-3IHtZToUjuw6VwRbv+s5a6hS6ks59WNm7IjNgNagoVEIw9p/HDR1wjegY3EQ0nVABExZCqHi4csGu6jVmIOXpw==","shasum":"c4ba0d61f6ab5d5a9fa3fb9b7f603563b93d7f57","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.1.1.tgz","fileCount":106,"unpackedSize":225130,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdaNTQCRA9TVsSAnZWagAAnhgQAJm/MOHmqFqybifmpSIE\nil73Ji7DjO9ZW4mdEIuvaJOxVgsNw7Awm4DV1fpsH74qznnTZSyD9/Bc685X\nWy/C4l90YJJ+Mr/GR6e2bwnjtS7lG3MyBrJEGkU/1ejoAXrDYK46apch06S4\nKakGadtRfjT8sLY0dWM0U1ZVg+q3qn7gRNK94WzHRfDVo3osG4sjr4Kvjrxc\ndMNLDJ0hIwzeyeFVBQKEcygvPL4vAWeQWwAE+TH+JAJHZ/qCWx+QnM+7pY6C\nhIlWIgCCgjKYHjDZBg8FwMmYqm3jcTWi3/51/Iws2L1QFE4iVShp6qVj1STm\nW7JdD+GoJiztW1r2s61BwY69AYGPGZ1Rgt+Z/uWbekexD9dTQ8fygFqZc4zC\nHKCwoPjOErpt2BaM7gpH6v0+Ncizk1zWqV/3feVQsohl1fQOZDNdmV9SVJoI\nS9Tb4cYtRPQl0CjjWFG9mHKdW27IkJVkID5t7D4uxuDJCcEWDY4H3IQghFU7\nRr62RIGeLhZXMdSeOhqKsPTnbsYPpupsr9hLGIvb+IJNCwwb54rdSdft1lTx\nQy8N1hn3l7C9eG6jwoNzZV7CRncEC6H5og34wOYEmAZDIcYVFLG4CIFB7x8D\noU6UEz1VyXsi5GBg24aL2SyAIsNmJd9UFAiIjOpeQMJ7G6PwYxn4scZ1I9yF\nr+no\r\n=DskH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDg9Lhwz6uMIKEb0Nk+701CqEUtCjcIvzXfF+v9N7aWBAiBD1WUNQ7938faXg/y4yrmzAdLgRYPuIARzwbIEEy5Pmw=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.1.1_1567151311447_0.8571905692610071"},"_hasShrinkwrap":false},"9.2.0-alpha-2":{"name":"micro-kit-atlas","version":"9.2.0-alpha-2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"3bcda6f7dcdd57c12ffccf7754053e5adbd05685","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Required.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Required.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nObfuscator\n-------------\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.2.0-alpha-2","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-pMXjVV+UiPKEbn+FxSWaJe5lLoafTaZtlDQQEzLR870HX3qW++nge313Agz0gR8AXzrHtuBME/DgPywlln+BKw==","shasum":"45c0ee9d99a631ba9a74a9ec6c4e903647b747bd","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.2.0-alpha-2.tgz","fileCount":110,"unpackedSize":267382,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJddf/cCRA9TVsSAnZWagAArPAQAIvFCsKJfahpBNeOyA2A\nd9i2hJ6Gmpcj0da1ohgSFkJin6qKr86oI+KJuQ8GoH6jX/kY1V+RFZ0zOQeL\n1tolYxuZa2XGhS9kimF6U6jRJGc5sa4P4bnEIty002KRzDp11gHNQJjz1kYk\nNFV4TKNQ8JRoFxNVPBHUYqKBzFFXHrnQpab3yj0bEGclxuIl+LRWh4iDzmfu\nDAdifHu44tn+PPkBbzyyXeNQQ7rXlXeV6rCcDxaCP+GERTmC6RILlAMONFvh\nlMHmb7mSRL7UQRvfjxdxAQ0W/RAqM8SR4OkSDTASH60dN+KThex4mmHZRAEV\nQYwsfYv2btxsryg0pDlBD5SJsO2n5Fbd+EtoxcOEHggrFellDjxGEfZFHQzG\nRLzSp44RDDsqD2ipgYjDh5VLx5bU9xiGOj5mziBjwcljSNEp+LfwEVFRHh1X\ntmDH/Fm4wrvHESizpEw+PbfBMvtasm1am+dF27jfJztarjoGuySfwinQcN+C\n6zpp6Z1Dlex5YCK+etucpoWQZmcrqk/qd6JL5ie7H0hkA0hq+coQkqwA6G/t\n2ZWodHQ7cTKbPT4HHA9igLbcGU8qA91H+cFWfzzL+OBCpQDtE6FlKP+Qi2E/\ncUHgecTTODryVDvk96hOm3kTSJEAmHGJECdB1cdR+b3BPpdJ155dW+jGvi9s\nFKrc\r\n=4PB0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDH//vVHqaw8C4hR05xlmXlB2RpobafnS5LTrpuCUcqhQIgKf+5phb8ohG2cuPwS5wIWyvH3z845Fjj6L5L8/TMP0E="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.2.0-alpha-2_1568014300067_0.054586454472242085"},"_hasShrinkwrap":false},"9.1.2-alpha-2":{"name":"micro-kit-atlas","version":"9.1.2-alpha-2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","build:lib":"tsc --declaration -p tsconfig-build.json","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"dbe45b4640f520d43a410e18b409107f4866aa6f","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Required.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Required.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nObfuscator\n-------------\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.1.2-alpha-2","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-aoWjh2m+zhZnYHVp9+zeg9L107F9phP/X3Rq01MR5GCOOQVDWw4OYtRFizS9zPuq9xaHOcQFS187zW2c8UkWbw==","shasum":"4e687169fcf3141c6d5f01848c91658229d9dbab","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.1.2-alpha-2.tgz","fileCount":106,"unpackedSize":227461,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdeOq5CRA9TVsSAnZWagAAnrYP/1H4LFBy8wooEsFopZaB\nsWrqeOPcP2L8kj7+Bhh0yHMEtGApcivtXkfF6xPHL6O6JZoq/ZXFDuFMW+h2\nrdmEAr7O4fHkhBG8NkLJgf+Nfybi6ZgMZ0/Noo0Sbqbi1aslcIxnOcekfBT1\nHOk2k1BfMer5j2FY+ZTtUT8tfvxamMvaUriLgQxouQsTxNc3Ky3UYhukbdi/\nbvi5qJrr6VNKXy3UdxzerXmzGdxHaP+pqIALQte4bDGP4S8DrvpWj/q4Ss2T\n/SbJKWeHjl9Jj/EkTsED5vRFRMpYypfZcRXHP7Vz8dNWbGzKpAkYynZisRaO\noFUTDAL0s3MJ28HJwMdbgrmGP2/hiyMZ9TsJ5nJHE7qwuUh2mzr5zMzBYtPE\nCof8/cJzH+YZ7BKbFwCc84BTf5ZOzmAVlm2vbWzzZpzaHINbnghKmnkvAFMV\n9K7JjtNVHXfkc5WJ0NXPyjZMo9VPAMeqBTQYQxW9VsqRaV03NTru5NGxzKOp\nbzqQIQWHax3K0Ncr3UlrV/CigsBRgXz7/5YdfDw6xNVl8ZmLiTGU0nbf2BkD\nl8rZz1dIueaUU0Zht1maBdSqo3mxFP3lScjAgYzQfRBsTusjw3r6jxKz1SK7\nL2NQ/vrmGCHvo3sUsGun+69teRbGJoeUnlJv0VVaW51zvB9jfBqoI0+vaeOk\nfYYk\r\n=/JPj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCC0bVJkilCI7H9tvCmIuxiGu5DuHe3J87lmSZjW9+/owIhANl58C/uxr2gp01zvW4sMzxnmVwYBGbZjh+/DsrbeycJ"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.1.2-alpha-2_1568205497099_0.504799815616372"},"_hasShrinkwrap":false},"9.2.0":{"name":"micro-kit-atlas","version":"9.2.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"d8cb485ec96fcfa802af5434ce1ec56622c13fd6","_id":"micro-kit-atlas@9.2.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-5Z0fedyfd4szNAt2+6/oxlgDx6Ddx8y+xHD+F90D0BbBOMb3+XdUKf+OEwqhWJA3dszGn7470M71l+nMXiC23A==","shasum":"ee4a7c2ed1db03d90fae1f6f2329f31cd48dcb88","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.2.0.tgz","fileCount":113,"unpackedSize":272134,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJde4b9CRA9TVsSAnZWagAAwvoQAIiDQnc5NZsc1QSBx5mM\nKWC/+nPEIo/8Zf+RWrbfvj8mk+QiOTKTSScIISXisDPGTLBpaRcSZkSaxLFS\nUVV1KZCtd98Bjp4nbnH5bL7S0PthfpzicayUvWKZYGUdm+F1fbm05jjUIJX4\nwdQApAgKdaiLIiw8XdeoUM5vAjnYjZ9vYv2yvS//tP+oEGbN745Lfhs0uuxO\nBSXtjNXMOimyfJLWKcT32ec62YL3bDy38BtsClJVE9nDwf29/gYAgGobrOAN\nlww20B1MZ3Pu7/cizCwUGE2cMev7hfSvDQbMUCfx9+GXLa6DPp9hRWs5p4Y2\ndZ5gQKjYYh1zHM40IWsqXD2ImqXQd6lnixRaYsOXIaIgnR7NA/82UNbrJXjb\ntdOoc0gbSyf6+KP2rfI3opEVinkrmJ3tD9OzKhVS2zhZDtYtXu4JoaJLIUtV\nSQ7tapY5f8AUqAFOGfTUGproIrxIszP2Y9qTL11NsYhvZWei8/L5jUbFC2p0\nejb7N6UHMQwbCS4U6dUPYBh0ARPeMS193ECW87vhDaueu7284EbfIlvO4r5o\n9/OuBwCacDeri+rBdSMB+Er2OJqDveXbtCV01YAQpzwY+04FD3qj6s6w2fHr\nR3sLv4A9b6URtgoy1t6u7mHcPg2H4lS4RiKG2/XpcbrOc7/7wgVtF2Y2sVc1\nQ4Mc\r\n=uFD5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG/ymRvGuFHKVt0s4lcSP8bMzivm0aQzZJ3tmqBUx2fmAiB8op4Kolq7QbyE0RidDPIiAek1SDO7gH+RZ/7hkEmXPw=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.2.0_1568376572527_0.5472328548685919"},"_hasShrinkwrap":false},"9.2.1":{"name":"micro-kit-atlas","version":"9.2.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"a46d5d1fa6901636692e11f130be5667aaa3fd0a","_id":"micro-kit-atlas@9.2.1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-U22ai7PGZ82At+MdJkPmqYZ3wXWfz67wheZRLkBJzf1DK/1/O8wtHZ3qSg2MxnRcyXZMJQvrM7LO1X6NeahWBQ==","shasum":"3c0cee1357812dda78af1a18e0c3a008ed995b26","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.2.1.tgz","fileCount":113,"unpackedSize":272256,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdfzXsCRA9TVsSAnZWagAAVMoP/0OYnVJ9tbhty+aGWL5O\nwLsWNr4Hlv/NkxwchIPACJFpVNuHfojvSuQteHiDXUQZ6FhoPyGET1LW1W6O\niC80eQazkv3Jvvnstd3F9AXjvDiZa9xehANo1UZKK9PnrQyIBXT+QaDVgCdj\nXCdlgUKyuDRQX07kXrDqUvtMqp4OCb1YydgrjRN9V9K2uA1rbGVM9lpxGRV2\nP51hzhjtnAB53gxVW9WFsLjgFrhHg90OrRu7hzsxjeCgzrtR0TCzZ3mzwTUj\nGROaUe8zMrjHPE9wY6XfU0HfTG7ODM/c2Smcgy17A43ZHcUi0TRK1CpMS1H6\nLnoUu3a4iYDS32dxTO1qKHUkq4aOxfdua2DI9xpDyRMNPTm1IbNbI6qftoGF\n2HPUeiV/UA11JIw9i1gwA3MbE/QjGm3zmuGyMp/7a2I5Okzsdyp1G5QMRHhT\n5to9FPdhGYqhLoBwywCvwCjnNSk42wmBCs3F83Ywapalla10UWfiMEmHTGEK\nuxiRQf9ziDOMVf9HzuX6J3uQYzitX/KBdYH6OMDmRJrahNUrq+OtYMzRanLc\n6t6J9Gtfj4mP5trzitzl4yhBdYSWgqgGN6ff+yvSLvA3vUztUhk8WtM3Qup6\nVeaMlVWQzB+WVQmotfTr4Ylv6a9NYQZGhUfDJ5+xHm1/4k+7ouC5Uxadehc2\nk9iX\r\n=dTQu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQClzuznImHF/Jk9pbjyWApfRIfnIdT5MD3CiUxC+/UiJgIgYndd239zQLgl37zaT74F6ZwhpK7zUkcn79wWd5NgOSA="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.2.1_1568617963816_0.10289394701563204"},"_hasShrinkwrap":false},"9.2.2":{"name":"micro-kit-atlas","version":"9.2.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"030a01eafebae8295090c860d0fa1bb954c9d86e","_id":"micro-kit-atlas@9.2.2","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-R01dukAlh1LeJFREDk+F2tfJVXnlWI+0Mj3QTspJpbIc5dndJFJAh6FPHO71EAIXwSflwhso4oeLcaeE15fG5A==","shasum":"4dabbcaa2811f9b1d445c45cd31fe4e3febca9a1","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.2.2.tgz","fileCount":113,"unpackedSize":272128,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdf059CRA9TVsSAnZWagAAZLIP/3CPvymHxlQRFcHkhNIX\n4hjgkA5bDMzCpVT2bd07ekMg3IMARZpuY8RMvaCh1DG0ZFQLexjgLCCkckcU\nmi2rTJhkrI4Pflf254COx2crbbkdN6wrBG7vh5+tcyjQd33YdG808dzKWKs2\nJP8d+Fv3qaN88Vm12nkyh8Q7BtMMnaZ8LD0Kj86cRvJiP0p2AkxyNeMcqu8p\nkEHYXKtVznoAbgapchLeXPeqXX2WM+wVE8XvXzAnJhNQh6h0N1xsODq3X+Rw\nC11a79kHAeejc1c9EJgErI4JCrVuPcihpSqkPMSXEf6KYhDR7xCQC8zp026u\nu20w+TnB/1GiAwuxufCZOVZhjP7RS5j238zwmxnk86EaVHN0sRcLUWfXQvcv\neb7N0cfUSvelLVknnJJhK2Zt9m865LCoYFmOnelSi1YYbtTGNpNXjHXyBQd3\naNr5mZCiq6Hh4rAQgzGbwRCCtBnmIfHSHdpEEazgfdDRyfqihv4rbkoPY7bv\nZ2zz55yE6PoD/lmH0MuTvNj+ftA++nBa/aTL/1kf2qb0+ISxh7bXzPllUXkc\n4FRwiGPAVlbPRjDikJXqnNgp7S6e4awXVlyKEe84NC9P14I6orMXwa8fa7aW\nFQX8WeVyPD12eeYHepkLqgZwY7OAtLeyhTBQRIjQGg8w1khPUJUDJblcqbIF\nW2G2\r\n=hEpd\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCID8r0Th1RSCubQdzAowV63JEaxAWhNe1MFIcvmgrtGkzAiAIUGYwakr45alrK/Ys551ztDTKSb62OEw3Khoy2U8Clg=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.2.2_1568624252484_0.9470524251936592"},"_hasShrinkwrap":false},"9.2.3":{"name":"micro-kit-atlas","version":"9.2.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"a7cc22604c8695b433193613be69f00299a4b434","_id":"micro-kit-atlas@9.2.3","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-Xm2TWz3oiPY22XsbnPkgSAXjjbMfF9ibPzUflvf9Z1VtJPhS8A8y88N+olRlmM7Oz79tzJyxagNzTOVuURLaVw==","shasum":"9380cda0876e1fef525185e3b1fa58899af53dcf","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.2.3.tgz","fileCount":113,"unpackedSize":272067,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdf6T6CRA9TVsSAnZWagAAF6sP/33tSYmutEkOUZ5h3cJ2\n0ngGX/jxJKfk3u9JIAMMtEJ5ibFwo/1XtRdla2DSHgTCUDv3kCk0dXLS1EUB\nW2mLymE71h9UEEgxhUCGElvlIje/aFctfjUn4w3vmt+l7yUtOPGnIQACQlWD\nJ3Aba4s8a/OlS7hnn7WtxjM8IvseOB6YlIKiAvWc5e3gF8jv+b//LduBgl/9\nm91pFjJP2wKGulBENV3lzDtamZDHl/djFEIj9UIs2Vw19cEvOLdSpPyjmwVk\nY6qcyOoqJtL1HT/oHHAQCd97/YFW8TxJaUQceZz6JVnqGO20eUkH9dVIHdBG\nmgUOISUccEscQQ+3lZ8MEOvBBGvgxiI6K0v1Ch34JrpbCsx71vxU1C/mImqV\nJVFHpE1PW3nuDClOeYg1HKPJUr44jhnOFIOi4dVsEdYigRP52+yhC5cpBrs7\nHQo4A2v3lm6rUBgpff+QvwYOxQqvXuVRLQyPGKqEXjKLs2nReKuBIUQWiaK7\nKxms/KdQZS1rhe0K297JaJJXxAZRY2k+eMmLfk+b3VT5BrxiiI6RlLf0DYEC\njoEHNDhcXv3wBRo1t+SUbVwIRftaYdpGzz4TUJik5XwhDVnD2niBkoPr9hiY\ncsInYfKgqX9YaKU/lv3gTZeBhqBzndT3wvgeRXrdCV+rz9kQIHxsbbXfhok7\nuRd3\r\n=P+7w\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCHW1NQNEs55jXv1V3TRnqDHBXyqB0zi7LMB0ZaF1iw4gIhAMW3SvGW9PDNzKhrEi0/VoKui7UxtLxRs8GSXK5MHvIm"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.2.3_1568646393239_0.2746585403369268"},"_hasShrinkwrap":false},"9.2.4-alpha-1":{"name":"micro-kit-atlas","version":"9.2.4-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"72948e089f8c6f8898d589a7cddef87e4c6590b0","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nObfuscator\n-------------\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.2.4-alpha-1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-40/ewf3qmzQkZ8quwppHqwRPRXTF2UJqAofSPZMmuRNSoWKJT/jwly6BdCoQEY8ieOz+GujpNhUDbimH5TG1Yg==","shasum":"73bfbbdd4e749277aac506c3c91b76eeae1c5678","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.2.4-alpha-1.tgz","fileCount":113,"unpackedSize":274572,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdg2dKCRA9TVsSAnZWagAAF6EP/18ewt+cObJGP+f2TIb7\nbO1HD0/F75C0KRk+i+L8sthg+fJzRx6mQeXiR9wxSOqbq3tgVRIcKHZDFQxX\nOaMHwUnhmRZHOtROSmu/9axhEknt6frqOWT6UeB6ZYsPIDtiNl2bm/Q9n9qV\nyVqptyKDQN/u2pB6HQqu7gBCZcsW6Lt7nrypJHfO1Xnenep4TFS7rrKAoU4+\nNyMY6+OVmnSRh1B1TGDn1tSg09XfqIE3CBdKYuktpaUt1hfShbks90COSymE\narjx20qoDTwbd+WLzfJk4KkXLvkW0BJ38Lu7H0f28cyMXY7wE24IvKCfmc70\nqcs6yJ1pIk6y1pvoG5P/ucJNjK4yt6Y2cbePslSgmMmESZ2cdEVeumwaBbIJ\nwnzyrAIHfZdslSwoZOqr1oGM+p1Ab3DOyi5bOi6PIRSeMJzEcGbr82dg6inW\nua08+0cgXOqgHUq1ySAX+OVvLGArjIv4Pcgx1I2v/jpkltsE411aOFgeu9dT\n+kudz0tqGtdKy1DlvriX7tU5IMTz9mQ7cgq18Ws+VC5/P89GmSjqIhsukMRE\n90iTrE85YctdflerERKJuDwEesqIKKAWWlKY30o/2gL7/05LfpkatNmcXMMz\nj2hhUDGQIOLgBkC6qlp7Z90syetvWNHBOYZ0G8Xf8rKrcNA4tbJJqRc/gN6B\nWkjO\r\n=86f5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDFC67bi0Nry/GXK9kg05ZcGPxNIjIvP6SBHlafETj6VAiBmAvw3EGVqcgLYDeiYw9aExYgY12Qx8CGDxpME26ZUig=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.2.4-alpha-1_1568892746264_0.43549732103508765"},"_hasShrinkwrap":false},"9.2.4":{"name":"micro-kit-atlas","version":"9.2.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"62f5396ec4649d63d2de40f0ba346337d696c4d9","_id":"micro-kit-atlas@9.2.4","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-iyIUnCu+hVloSy/XCiUdulMydryJ0MS+Y6tWerfWpt30iNykixRMgXc80Pv/VoVYL3VcLN6VSXSXJqLFkSdCZw==","shasum":"1cadd8ef891444492f2f31a09d9f1826e0e343af","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.2.4.tgz","fileCount":113,"unpackedSize":274837,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdhJL2CRA9TVsSAnZWagAAXNYQAIiwPttupp5Mmx6GMoSn\nZeWyVSxdz7kKoGVSVQbyT3awT4gSHDFw0hyLGQqrG6wjAJ7vK9pGMoE9wiwt\nsqVk6rE12Ei75+M7hkH9gemvHLZsqvdyBk9LBQZW6fCCuqcKhdWffmrySTDC\naPtG1KxYHcExsVMOxNBbss0gf3BSYRIjLF/CWyZb3OofxIR/ZM2o53JprwBK\ndhDxAioASdMbjd+mdeTxHBcyjzsHYGAHdS0DmQ7O3JMaMCvve+YkInxa4luh\nB7YtbBP4dmF2+2t1RjAG+PZSK8Svxl+BBZoS6bpndXUJ5H5eb8CDI061oY98\nl2QfEZm8Yr0cOIZXG+jZQucmUzpVSnSSOhSveFeakDPcaz7kDMeaU/QeWgTx\ndqJFCpBkZrwNYL9bra8PoyatNklMOwGKcXT+PdjN1PmeWXG0UlGAi3UuXDpg\nX9vwR8QQPq2oGj5zZn+cI76jd9hgPxlfqedc3tfCBV+2Aprz0z2u3blzHqxT\nEQyXdCCWq0/Ox3OKu+GizMoKdaJ8LWnRrJaP/TF5r89efiycro0087KnoaSr\nLQNeaylJ40Hwx6LFIpetjT49lqHzzybvrwf3ENAMelRZqoRRad/D0Rv+9/VC\n+bAjjO1rDN9otLHLs0cIqmWJolOEBTWG+/hVDb90xXyPIvS/fHB/z+Q9MPWA\npb1F\r\n=MCF8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAXqEarlK5QSLcvGD6+mIKgI7Mt11xkdj4mae5jOsdXTAiB29IJDIaiMMPZMnTcoH2iVCHBvETmPzdHU8NC0b/6jyg=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.2.4_1568969461065_0.3541951902601044"},"_hasShrinkwrap":false},"9.2.5-alpha-1":{"name":"micro-kit-atlas","version":"9.2.5-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"6213606ce840753f59786eeb206361e1184229f6","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It should respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It should respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nObfuscator\n-------------\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.2.5-alpha-1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-55Hc1BbgM/qR9eJfVGSweqoVTWb1QxhgKewulMNddyu2ZKnhpxcS8Z3JRbKS5s6xLhZ8exOuJHXSXtxxL34BsA==","shasum":"13d0a06869e8536d9f80a1f75d8ea365833f5ddf","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.2.5-alpha-1.tgz","fileCount":113,"unpackedSize":274916,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdidMACRA9TVsSAnZWagAAXPIQAIGeAuJ/ZzD65kHJ7sAW\nMpe3zTaAYCQgOS3ctSysfajPJoUAdUBSk88xJM/MVEiqwTZj1shFUwHS0pSG\nomOLvH7Us1tdL9gP6AahfEOmikPZgZ+EPjhhpPg7bpWRBsUNu1EfTpjoybAh\nzrZR9DHTOy3r4Gp1O71W6xhD1MfqhEChGLI5geaV5tcoagHakzUJD2Cy9HTG\n24qFNOsvj2dVPI30IkGVaCUeQcGC1C7AnjO2aAmfz1gMkEzIfUEO0cu0vQzN\n7PzCOFPYBGKnzLU+hNINE5UiGV7lprz4C8aW1sBhB3eeXT957ISpI2Ei6Ep/\nGm7XOVhEHtl1H90Fm77zi0l0wvR2SvzbNKlfXZ/tl6rjok+8qf9ABCL6myli\nR4Sjg8ty/zJ2ri/lTO8TEB2Oc9IoJJ410qzIxqCUHoCTdU+lVuNyLLjf7x5i\nxeJJ9lFsEkSbvBBbSzmropUbmJmQos9+hEECi8ERFW9/jthJg3hBBN8ZIlbh\nDBc2QfvBFHQd5zzYIPDlKxREHULBpjYTdJ9mvS0LKnDNvTvw2NstNuwx/ldQ\nmH2BanC5ZpZPVdSqZWPk2BvIvhKHzxb8QS8vNcCBeXi91pJxWuVHYydi/vSp\n6NaljrhQnZuFd1v4QdMozyb/S0wZhyKVbeDv4IuRxB60xdVeQMMofiOqWXMG\njLvQ\r\n=BAn8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCmi42EjYhCiyUyTCKmBvAY2mbLiIBXOwX0PH2dclb7RwIhANpR3iA8x5+jZ9Ho0BXUs4yo8Wqdbx2GYHjt1k+iJPp4"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.2.5-alpha-1_1569313536092_0.5097062317958017"},"_hasShrinkwrap":false},"9.2.5":{"name":"micro-kit-atlas","version":"9.2.5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.16.8","@types/chai":"^4.2.0","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.34","@types/express":"^4.17.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.14","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.136","@types/mocha":"^5.2.7","@types/node":"^12.7.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.16","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^5.0.1","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^2.7.0","sinon":"^7.3.2","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^13.1.0","supertest":"^4.0.2","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.5.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.509.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.14.0","decamelize":"^3.2.0","dotenv":"^8.0.0","elasticsearch":"^16.3.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.11.2","jaeger-client":"^3.15.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.6.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.7.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.2"},"gitHead":"0775e90b53b18877ea36d28e3a3102b227f0fa75","_id":"micro-kit-atlas@9.2.5","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-nLN1WfSWtsDJhGs49flhTOeq+TLNqqyzhql5f7JqAyksgl69SNCZvilLUJqVHrYnisGRkubwCjUIMaFgK42Rog==","shasum":"552834881e9e2308a0bd92f84935573d16e6431d","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.2.5.tgz","fileCount":113,"unpackedSize":274908,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdi14vCRA9TVsSAnZWagAAoZoQAJocjLADiAixX7vyR0IX\nwzTqn9stYX540yszrn3/cOZcgr4L0KBxLuMXWrxWgyfF0NB5lkyXZ7+2/cO/\nKY07zwJt2jpmYJf1q1EJEtpxh4uSat49k5QjCBYnhTtCLgqCNapT9hoqfzUA\nTuL9OjYLmunUc4p9M3arsSxqt3rPmgIFgsaXA0nos0OOPdc7KjLUo2OnKjMm\nMjtOA8a2hly7P+jVpGtr5cUPT9D5kvoNNwl+KXVLfKzQOMBKtzd4vnzZaTsC\nxUYX08UrqPA4zZ2bOOicRvKGnYHZb1U1XqPCTCX8XRavJ6xR8gy1ePsoBqHs\nHn/ucMM4ho2GXbclrOjYEC+gnzlPbT7xJ1eaSa0/blvnaM0Zbap5rhmZigFY\naE+bTnJIHX4RC/CW0KpKLjT/j1SLKWR4E/jdXGsFuIC28+owu08TSjNbZNfW\nblbZXRpd7O+CqJlnY76rKbrgRpHA22CP+PLBWCdvaTE9sfGl+YXGrpRPoDLS\nfsdsLo6brDoilkhNuXLlkNjTENjm/rXPy5qrPZOTZkXpA7NkagWg0lFcqJAg\ncgT3FcfvAMkhctzN3QmnN4jDgjjAbiHBVabnSU8cbALIuXKnAQBBkDmigdYE\nbEMuZKFUAAyuYBuLIJj887yNY3f7cGCysb+N16//17U4RrOQFXOv/1CSEOOn\nAhZU\r\n=EiT0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEAJudcOJFuIQgj19+y8krJGuaucZNbC9eXqOm85l67pAiEAntXkoweqrQWXIJYXOkH5PO3eh/xVO+D4sC0rgsezlyc="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.2.5_1569414703215_0.6783130173476961"},"_hasShrinkwrap":false},"9.2.6":{"name":"micro-kit-atlas","version":"9.2.6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.3","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.140","@types/mocha":"^5.2.7","@types/node":"^12.7.8","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^6.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.537.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.1","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.3","decamelize":"^3.2.0","dotenv":"^8.1.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.7.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"da39184ac34cdc4e65f4039e986bbad28de4971d","_id":"micro-kit-atlas@9.2.6","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-SHMTxAFRYOEnS7Si+XsDzg1iiI5XogqTvzPCTxEXaqUn73Q09Re/sI1mo2BXLdn3kbU+2S6daKKc4ngyjIfipA==","shasum":"0eade2c414e53ab136431b234c04ffc604c8cc74","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.2.6.tgz","fileCount":113,"unpackedSize":277054,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdkJNtCRA9TVsSAnZWagAAQg4QAJwdoniRmm6BrZqAhqcN\nKreEXfXOFu6+NA5Zf/O/H30Zoat4MFRI69CnQMBapAu9uY0gVcotuAuiXNEs\nBlEjhADfVdnBCtJUj957o9DiSohg5RbQIWuCyA6xxb8U7cFR30fqRwmcJDwF\n0nZt9NiPlRl2QYyHojxUl7D02JNl3iYQB/JuHEnX3JLVSueKbbwyJnSwPUkN\nqGMa4sbYieL/Yr6iJ1RxHJVC4R4pCCUtYRKLUAgsd1fDJA8cLs5+NiZLPi/2\ndh2PHObGp56iNY+R/avIWa6ajVQww21iSJLnoX0ckSlIhQnSKQRnDDTF29Zg\n4KlYh6Jvjed8sPYdYTYfXXcSj6eICfg9xgjoQt6/5TmezI4wQCExBBt2XgNt\nN0V9wmoyEXsfOGDMMH3r5gHuKCZZ+hL9c1BxnaWBNk9uEDOimCERA09nZTC2\nMIiP4rGADS+8683f9YoInbJ+L8YRydNNrLB5Xqj9q5p6RoQuF9Shwtr2o6Vr\nMgTWMDWKdYQQuYzpHHxGe5vpFpDP3U2jURwRzXa6aG3P7Q23x9PP/YfeKrUL\nTnQ5T00DnILK7DyQCQDN89PTYzXSsuE8ih2rxSqtEEdOtkuVq2wJnQ7tQ6J4\njXfZFv4CCNW5PbPheCMe0c+A1mH2YII3LRqKmI8lnD1Tt5jCtpzBE9tcN45d\nugTY\r\n=3av3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCs2lUzCYFivCruw3L2OFtghWdrrK8qBxIdxlyRsW3xhgIhAJDUrQyUeUTjxSH86Z3wShZa5v6V7JfGLROBvJxSHBiW"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.2.6_1569756013019_0.6618410561140697"},"_hasShrinkwrap":false},"9.2.7":{"name":"micro-kit-atlas","version":"9.2.7","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.3","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.140","@types/mocha":"^5.2.7","@types/node":"^12.7.8","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^6.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.537.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.1","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.3","decamelize":"^3.2.0","dotenv":"^8.1.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.7.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"234011fe43e90be9c8b6823035bd04ac9bbe607d","_id":"micro-kit-atlas@9.2.7","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-jQ8wc8RB/ZN0BcTFWbDtaA/VR8iNn2eI6v0dtGOUn17En7cWtRYP0+SUfEp7IdxXAkFGM6XjjBUW66i7dfzs9Q==","shasum":"a9c14a7781d876c49d5bcd882cdf77ccdf63f655","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.2.7.tgz","fileCount":113,"unpackedSize":277131,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdlGGFCRA9TVsSAnZWagAAB94QAIWA5ePMjWiXnyJ8VOb6\nw8msoxpNSwc2Op7oTYhOAjcEdFRFU8zlh4CkPu5K42GWKqghATKLD4ZXyK9J\nf8jiFHYMP4dwIob+5/3vGPSQDve6mgg9rbSgFpZTQjRU3zU1GBF+0iqG3j5m\nfz9Qi/9LZc11mAE8vWFHIZvgEI/wSLPufc4ylEHb1SCdutXUcNM1A3hp95R7\njD69Blzkj3EpftqNMiOKuNZmphQD+fxakqiKD6V93CQ4mMjsqaD3PnVm07tk\nwnSWbpyJ5nyXS/ZHnJkbxS58JkHlnPybJrzeHqzZLB12wVUQvpShIqJ2c1TL\nfrc2NVmh8uNdOUVyHKHfH9L3V1tdBB/pWKJKdnUT9GPNFg7YopriLSkLFBRR\nJh8FzcelShq1lrYDANy85Mx0k2eyoaTz1fHNlsadaQiFU0ntb/xgeTxoR3Uq\nt5SPYXfR3P53c+JRD3vanKLdfYUoTCMbALY3Obqao+ADQT2Fkt13eUwe1sQ4\nMBKKWAbraotcir8iUnJyuMSdDhUKo1KF8+zYyIAgwUJ0/ddMuhv+pS4O5P3b\nDmijXqELDWu7kGRmpWRWvTTX1PprIRKGqHoT8hxAxlb5MknNhI4yuDstUJmE\nGwGWhlPrb76/YhcDHuXQy33+YSM/IvR78wQK6q35slJppeMezwRvv7aTB6l7\nQjeq\r\n=fR+h\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDSVLE8Fq+/3qlorp5LksC4s0nWP0WyK6l+wFNhj8FEyAiEA9gprOiFzbnnSxfrzP2sXVA9g8AqF2yPYrwGUTjLG+I4="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.2.7_1570005380795_0.16295748238245467"},"_hasShrinkwrap":false},"9.2.8":{"name":"micro-kit-atlas","version":"9.2.8","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.3","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.140","@types/mocha":"^5.2.7","@types/node":"^12.7.8","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^6.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.537.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.1","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.3","decamelize":"^3.2.0","dotenv":"^8.1.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.7.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"22fcfe504ba05d1a0d8e1d34639a9c0f3e839b20","_id":"micro-kit-atlas@9.2.8","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-nSjJJHSPFLpXnH8ELKRtPVngHSsTQc9FMjJCRPERu4iRIaT+nvTffRrwJjQagI4XdeiYCGlZOUSQGvlZKla9yw==","shasum":"9cae87f3c8c533840302b5fd77cfbac01d4c24da","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.2.8.tgz","fileCount":113,"unpackedSize":277418,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdmuSkCRA9TVsSAnZWagAAhYcP/3g0uflwj7i/VQzYxef5\nSEhhr4MlBbsq1D+0OcQgRmANk80fU+7j1LDLocnHlrwlQqpqv+qVvcpTrFpb\n4yTHz2x03MHHltmhiJKy2Ir2OqJHSpIFRKj+XyMZzVcxuhKvYBWO2TFECxfD\nOwRH0/UQaiJepcDEByIEbT9Z/O0xvucOYWdvpuzEhGk+GLbvb1+pI1j0DQj4\nuL6UI8np6ca1CPVaUZaBEynUWlL2itxqt/1Zu5krIG9rumRm9DswPvgeJQaR\nk2RJ+TWIflTXW6Ap9ZTNUvWo7rXDyQ5whnAnp5QJmoJcVt2aKMzqogzoeYcm\nhSOgWlxsceczH1HZuQh2pyFDJsU3hZqgHfCC2i7zARxeEIH+U18Qy0BU6so2\n/ohudu5S+kmNit2U3QNoZp7f5CPi5f87CfwhTEDxktIVfO+K4N7XFI4BGEHo\njnQrLOBozOaq4v+iyNGFGWdFlQLx6wT3ENDqj0UWGp8G9h4ZlH3mQhWhWCxH\nJFFqPOXYUwoeY1iFugOdP2AFiboQGT3XwMDFYfDFoVNBrLKce1NaX/OpQlw/\nIEXuAkyYeWGCAfuvZB3oKkXefKSUnYP5ACWB3w+3fdl5gQqB27IrN3R2W+qR\nDlM9/LbqHMCBctPieMP2DAKhx5q/5KrZZcthOX/KFRnfblrXWwLchWmzEiCs\naL12\r\n=TUIX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGKgwGQmg0MYdScCbgMr4xpdc32cwNR147bFYwsDk3pAAiB6qNOVeNWNi3qfXlilw4+08XpXXJBMQTaiWx4yRupSyA=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.2.8_1570432163766_0.60342880053828"},"_hasShrinkwrap":false},"9.2.9":{"name":"micro-kit-atlas","version":"9.2.9","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.3","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.140","@types/mocha":"^5.2.7","@types/node":"^12.7.8","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.4","@types/serialize-error":"^4.0.1","@types/sinon":"^7.0.13","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^6.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.0","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.537.0","bluebird":"^3.5.5","body-parser":"^1.19.0","class-validator":"^0.10.1","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.3","decamelize":"^3.2.0","dotenv":"^8.1.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.7.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"42e4681237a4d9e58f445df8798eb025f3329b33","_id":"micro-kit-atlas@9.2.9","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-P49bGp/0jxsSmaqzVez//CL/TgKm1XIlpaBwkpiQNyV8fPSHNId/8d95AFQK1oENirCAziz84SHpFGf4diEihA==","shasum":"b36549b4cb505a4cf5d85bb2f0195d7d4a2aa1f6","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.2.9.tgz","fileCount":113,"unpackedSize":278503,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdnfVTCRA9TVsSAnZWagAAcL0P/iK8vENhYF5AW87hL16b\nXNzp0MCx18LO1aB5niHXZ6443cyqbOX+7HNYL6anR7d7VAGIbAeIhiScAcyb\nt2qApJV17eN7YB+0HPM7TKduBTx59nO0Lzzs5nIcSTd9HLgLcf0w74e1W3/A\nm8fzulw/02JbkRxYlY9MngJaetGcM5kfWHZf04BaXcIWr5M2f56WDu4gQdsY\nEOU9jY9B+LsgM42LUSzywYKykesULyd0ZMjeXn9jDY7a2CwN9Vk3xJ0bTlOF\n16eTTz0JZSSuEiElyLgrrb4Qf3RdVhRBzymphOpdIaTW9iyHSJdm1/T/hiG8\nMdLLrlZVIuG19+z0aEoRBMeoZUMMGy4sODrkrMCPrF8eeMExjPCUag4yduD0\n4nl24fdU8Vqz2mpp6/jNmkoghwiLiFcTAPXUbNyZn5TsoKaMF38p9WmJ8xqK\nx84vQ8fePGe9zSlqZ+/81Dsj04eYAPmJLFkRZhtZUk6mNmIp0t5q6u6KkiKh\n73SosZ7FRCfnST6qvTMHOEHyjcvjNtIPd2UrjkD63qwYQDAkTAHBC506mkgm\nPLwNXthM+rEKMi5LQ5Zl8L+k5turV317PaJ97ZlOvc4+XintIqC+NVbpyO9w\n2r4BNak4/55XpqU6/FrgXoEA9WJ6GR1ERCYjgm8J73fTn7RFeSNu3VGwCJ3j\n0VR8\r\n=RiaI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCqVaCNMBWhbkvsPC884ChWjZYk7ualuntb0u9+HUq34QIhAJxD2hlKQbk7oDtxuu1hyARF9VGK/2MrWCec7ERaLk3W"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.2.9_1570633042450_0.011894714116599259"},"_hasShrinkwrap":false},"9.2.10":{"name":"micro-kit-atlas","version":"9.2.10","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.3","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.7.12","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.549.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-validator":"^0.10.2","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.4","decamelize":"^3.2.0","dotenv":"^8.1.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.7.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"c7a2af7527b2871c441b214206ff07f5e42d5486","_id":"micro-kit-atlas@9.2.10","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-em/xMZfVhiPU6G8T1w/SNIHReHmaX9gwkTabqklSFvVZYYPGMZKRa5xMjs0KmWWpdM0kpTYczROm+Xd4sCJnMw==","shasum":"2804e862e76ad700dcc29ec6a2a64a61039a44a8","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.2.10.tgz","fileCount":113,"unpackedSize":279003,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdps2UCRA9TVsSAnZWagAAUrEP/3gkJQJRT//jCzax3wkj\n52dBpkmdvhTlXmY/qJxLr1R2l3yk4bv/Xz7xhsMwnGAFI9u4tthGmwmI25fD\nRgEagkQFRZae7tDjxCiQM5DF9iFocVgTdH2zLrLhM6SbSh5TnKz5M8YQbT9G\nzJ0D7nK/VZOqm23xx61SoOQqo4AP9IN0CIV2QjbPtcJbm6CHSZZWTE7tnhYm\nno/iOAV0VH1fHMaFKa4bwSM+Ta6hki+RY0hkx/n2oNVACM28LXVa8OjywcM9\ntXIRYnr4mxPIlvZI3ZgJgdVgNxCFA0BBw2NvKIaGOuJI1fekMcEsSt7yougP\naPpqmttucH0AbiPWpPY5Nb5G4XEf2GfbKiLB6CTwI3BMVn12zKZycwKpsYK8\nhvSh+adfO/Imfxgq6yn7FQEgMEUtU548EHzOgflMMyihvmy5DBB44Iw4hRTR\nYKbPZ8z3EXsSRpgD4G21aH+6ndb1us+hWVOWZk9Akrpl6HGl7F+K3Y4b3jWO\nX4o53plUtfMWgTwEkd8qarXKiFPDuhcUwZtYaWZVKkHAiu1IF54wOoPGfV4r\nArbZZrJJ4d2UYF1v2HTo4YUCy0gpx73JhQ7gzMenjBQgTAfMrogcPTTp4bgx\nd07JDjBmNk9oZsTQqX4PZeAAoNfRPJRNDrln1XrITS/gyZxXgf8OrkphRVsf\ncz9U\r\n=+e2c\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDoR1SCdrb1XfpPtbz1sw9Mr2v8bB4zj0XCf2TFRwuu0AIgGnav6BC2xEDQJe2SYAV6esYETCSfl75uU720dioIjcY="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.2.10_1571212691299_0.2559234203045775"},"_hasShrinkwrap":false},"9.3.0":{"name":"micro-kit-atlas","version":"9.3.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.3","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.11.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.550.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-validator":"^0.10.2","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.4","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.7.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"ed219273c6383ca64ecc09da96936433ed7e8c5b","_id":"micro-kit-atlas@9.3.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-1z6krfGJpBCglD56FNH/DbHnjb0xA4OUESZTMqOoqJC451buG2e76JBV3pAEDQJLz9MNjDYjK8ERGi0Ay8VZew==","shasum":"64f13bd2543819ad5759d019a2530d7d4f723745","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.3.0.tgz","fileCount":113,"unpackedSize":293826,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdrVlDCRA9TVsSAnZWagAAE4kP/24NWx054XcjMHr2JGPo\n9Xm3SbiFc3glWgN1GE8+rPQAJREGAzZrG/5U0/AdGGyMlCd1kMgw8iiXE5DQ\nQXPI55VCllVqKrki3kx4hhA1nI1ooNeyZFFRR8ISEqf0/bUHZmxNuh4IWn+S\njMCkP8O6fxDINFsitX0taxAnyiEnqID45EnTI6aiQ8bx3COINIwX9394aJQP\nmu587xN5bw5U8xQHwiLEdkXemgl0rBSpAlX1DM8rdKNvSpfQttvnL63LeFYS\nv3wD2WRZSEuxkdYa7P8O+n85sthAmKA1PewetGXZR1WAdym68IiQY1Gm02N4\nwMg/OcOYmpgdzrV93ugpKVnI4v+ZPDBibgo2OOtQwYp6u0LDjXtiVZ1pIq9z\nvFuhRRNAcAOfE0OeJgJlKpvu9FT76Fv52LXoBssS0KGOn653qQeFcZ5zHKjB\nl6qyN1GW5C9Do0vovU45u+UnqZLsnBCU08LZrL7l+Y1a9MC1i+wgiTHBKTUg\nWzxcckcZ+5tCJLwDIlLtpstIzFxCOViZasXOEbB2VqERgZmUa3Lgl/foW2uk\n41WJGItQmXCgVf8dfzZ75ka+dMTp1+/l0etQopE9cj+/fM5/zwxj+jlye7QL\nbk9lXALCYQapTwhn16lsm0fYqc9EGoaRgUA0Ex8Lote/nVKk5MEotRChYptq\nocf+\r\n=E55O\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCxfEmmTLnRt3rPvzxRFDZhMaaDq+z4YQICwUCwmYTxQwIhAOih3drC8eq2uLKVWidIFCSU7SeTKx6fQF/moTWVTrju"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.3.0_1571641666960_0.8339586377835964"},"_hasShrinkwrap":false},"9.4.0-alpha-1":{"name":"micro-kit-atlas","version":"9.4.0-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.3","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.11.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.553.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-validator":"^0.10.2","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.4","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.7.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"7d7bbaf458801cb144fb8b678ccd68b1e733fd6f","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nObfuscator\n-------------\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.4.0-alpha-1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-kHsNgMGM57sJm3LZl5e5kdhZUBlTcBqOdckCSEdA9OehFZauFlidfFuJZhlREug53GQq2KSh9hm7ZOfz2xG24Q==","shasum":"9cbb2230aea770e5cb8f8a8e6e897669810c358e","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.4.0-alpha-1.tgz","fileCount":115,"unpackedSize":295957,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdrbiPCRA9TVsSAnZWagAA500P/j9Eww+DecAAKktxSvfO\neR/Pe7DTORoFz4iTkCcQqSeIA7Cj7J2JpbBMNgT9TNs1PIf70/BUX+eRdm2R\n4mhZKLJCDDnh2dyx09nMcgRhaXoohGbdqKmXJvlpalcWigR/+ItFnXkbdVbN\noBqmkEimcPH7gC63bFry3grsliECGyrChrwajhLwYZmqpMh+tf7g67RCYbtg\ngYscZpgkFp7CiXm9QMe1gl/1KSA9Nf9dxnMECecV56QZQN4eI0wDerxgX+IK\nB7QiJhVERblW4f43q4KQUTr42ExoUWw9Gd4w88GWj6GOZOKF7QtVf65S2c8/\nAMCxAVInx0YXC/SgnlEclicuv6xlNxqRquXInE2mTGKKoEPAJ7khu4fGOBhO\nRKMqJdLrBOb7k1kol95wJ3dRK7cba4U7R6RbMuAM71Xb01hRryBnaGb1Ey5H\nskleqAB6tQx3yPOr4zXY5Vsxk8BymE78m2HPlFso2e3jpDFIFgqGrJMpQEGc\naR0ILiZ5hAFIJ3JJJYTHm85AWjAWpm7MirZtdLtz/sqyRXHTePWTNcLKHTpx\nfMTagQimMTf0sVkWLOtXjMgb+7YOVzhU2In0ADB/4nWwzLetSDMrOsYOhK57\n0h3AEfx0NDmSz+H0bs/MLaOg6WbtIqBVD7WpQZvItVALHr8tjhS7nAUhAmyE\nn2T6\r\n=IndU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC6ur3Ursdox8pWUiYReA4/rIz7U2xqDZwvnryC2B44oQIgbP/DUFzZi3PWKOg5SqO7/JtaQKpqiurJphnk/RfNYJA="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.4.0-alpha-1_1571666062695_0.3747412589307797"},"_hasShrinkwrap":false},"9.4.0-alpha-2":{"name":"micro-kit-atlas","version":"9.4.0-alpha-2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.3","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.11.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.553.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-validator":"^0.10.2","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.4","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.7.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"f2100498033fc695230e54da5e226972337a35f3","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nObfuscator\n-------------\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.4.0-alpha-2","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-vEeHR9fzfnIwdCpeXTRIh5EbQRy9CFQSxdpte9S49fI19DbVw0+i1ue6ocbk1BMb2rpqnr+dYiHy4lU8dHwIfg==","shasum":"f42898e208794cf669e6a85a1fe366ee29122dc2","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.4.0-alpha-2.tgz","fileCount":115,"unpackedSize":296014,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdrfswCRA9TVsSAnZWagAAsewQAJAs4XGTGh3qeW0Zub0r\nTtWR5LjSLt2e/aCgALgcpRmjvhlS3wzptWuXOnxgOcyWm1W7ocLX9O5Lh9c3\nVUaNDWhaNyMzp1U9EQmAinRN6L42EPTg8DL4KZfiPtvNclcHGoPlF0EAQAt5\n7WrzqEHi6boXWILYnIR88c58PaOuUzCc77rHhRewFXVLR4P2u5q/A079AsqG\nFTv/cY80/z18NjF8Hq0NBhnuybHdcPMlcQEJqTtSjP86Cn1RgICowMIqyGRL\nQTRR+Q25/dgf6dEX38vmKbWqkyI82DgtDPlJYrecOqjaF75M0NynHAXZkxVg\n1dsnXlT+9UcrnwnmhgWAiB4f6xfcRXb44LUyE8tnv9Yvur5jpHhoa2558jc8\nYpIQ0xlKUfFnYBCx/qgpYWwKZtme9rRQGSWfiQ+alAXtqMliJX3XgZ9u2qvY\nR9T7FM6g2jyq31hOqppiVNsfZiebDvkNI7gEPJN63P62MkwqkiZAKoFJAl1E\nfgr+iEogxdoB6cGS5v0GNUXW5aiZ6l6W2PDcjTMBtP3zCixjVM9XhT27ZQdl\nGz9a2sammFLLv+FEc332pIIyh+p8dBKkq9IpuHRWC2MhVKJRrJx3fKbWajUz\nQlMc0hdUD+mobhvIDnUduGxWPMYxliIfikiTEzWUGRKhVeRS2W4Gam+JypTx\npxAP\r\n=bo2A\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEe4a0A8Z37KOmC1leiiQJNgpJofVVcF63Om8dfUbq7ZAiAyDLGBRIpuHFgriEte6fKQF1HQUm4wan2QQwqRbR9lZg=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.4.0-alpha-2_1571683120248_0.0976662650822977"},"_hasShrinkwrap":false},"9.4.0-alpha-3":{"name":"micro-kit-atlas","version":"9.4.0-alpha-3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.3","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.11.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.553.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-validator":"^0.10.2","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.4","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.7.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"9c954e7505895ebd1d8b58d44dc8de54fe7455e7","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nObfuscator\n-------------\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.4.0-alpha-3","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-2Vvlglx0Q4eBeLfqXAwOAKSlHodaG24R0/pr0P+flqAyDFONGBj5hD7DyZmGwFlfwSP6hpzLnPuRqmr3LmRGNA==","shasum":"4a0b33d22eda65f6b30e7dd0cc89449b7ec2fe6f","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.4.0-alpha-3.tgz","fileCount":115,"unpackedSize":296017,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdrgDDCRA9TVsSAnZWagAAsVgQAIaFWYcMbbtjCo2GzCwa\nmjHW6FIQaECgVAUwChPheVvP4dyfjF2lu9oU2WdpEwpvRbXYoC158GbwNVy9\nIk4qY5o7M747uH4QEIu7GXtYCTjElgWNd1jjb5fhQ89MtRrN2lVJrckk/7pO\nlDNKaK4cc/j4aoIGTm4zFhNzonzyJ0qvmh5GBtZHQ+jHkhZ+cEhrbTn6aX02\neb5jOMandpt0s5Lrj3LjCBQ9JVq8fk/mUtgsl2kZ0A5mQH+wraUn3KmlDw4p\nLKD4CmQWxgbJ9e/bogxlYaToI5hC67dOVBB91sjHaiNq9G7cQcGIADZmFY5Y\njy1GBlVVy7uPbZe2p+D2TjCfg5fhbvphqC9KeEyOmkwmS2ZAQQlL8bUaFQIP\ny+A8+C3lz0EnjVgvoxh6vRJt6LreFHxomg/58pfR7ncfwNDPaWlW+MDBXW5M\ndUG8wketwUZKiQTlc2kZhfbu24yaKVy4qgLHJ7lBcyth5Lo7IvB9wYVwFTkk\nqBVIIRwtuynwnDWoKfzvkbnlql/UE8ylC/c1JUc8Sv7NZ5fiM6tw5P4hikKy\n99zFrASZS+jKWGzMSnRUE0SqH+wePM1zkpVfrdAMYsdsz1HyHI+W+FL4iNCb\n9EZdtGPYzC41qVEOkePhObsWbsNIgb8sZnXCwiHQjcEpAitXDTfJNCJeBszK\nJmFB\r\n=uIxL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDNVfG7cwmrn0MtsKLUMH/vVAeXbvNMPsOPkWl0tCXIGgIgA0+rTjMyrgn6O+yZRniODXcTCSNlDjGfUpk3nXVRf/M="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.4.0-alpha-3_1571684546456_0.7719229139821175"},"_hasShrinkwrap":false},"9.4.0":{"name":"micro-kit-atlas","version":"9.4.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.3","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.11.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.553.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-validator":"^0.10.2","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.4","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.7.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"88720d944c4fcff9b6e57ec212d9ff978c38097e","_id":"micro-kit-atlas@9.4.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-8TixOKY4lJ5rJUJc5aETbsNdwcSB7XDLg5TXjFY6uX2eeOd+e8NohkwIjDQC+Yb8VgsfOGGilaS7K4KZSUHq9Q==","shasum":"3dbb00538cd68f35d53a7cc008c49151d0afb3e7","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.4.0.tgz","fileCount":115,"unpackedSize":295785,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdsrkICRA9TVsSAnZWagAAQ/oQAIMi36YRNXmACbxxbk3q\n/2ZFwikacMEXxoih4YToCeVy6q95Uu46YMnCvfwPPm1NVKXhStZUAFmSwA14\nTgjIHUFU63stAjgwePf3hJLSOA8ZYyJrkLCartHPJROklMQ/hpEpcxSszdVq\n3hFO7CDBoLE2CgkzHxFDsJN3A4+8MTqgvU8Z9yGeWj14anoG5ztowkhwvoNx\n4zLbQMP9//KJ4XGlsQHjrW8XF3LXsyGzc4wHNt392j15b5GXRegGpn2eedoh\n8CY627Og+3ZnAdyaHMmG68Kc0jBfJK7o2/uNQM4c8paOvKT+AS7hY5Bwe4Tw\nmB2JJqUfUWLC6GW4zlDBKbE65ACUv98/jY1cql5MFGaXOzQvfrlGKtTG8UpH\nb/N689ZaTRRJHDYBGNoAhEbAjkOg7cV8cJVCpxq8Ki54u62vFYUukfP8Mu1A\nun9zGQrd8iE8qpv1lkkiwbdW5jmOK3H10jCFep/fM6Cq36mGp+ZkoCTkxQCA\ncD8FwBh5JwMhkKP9Y7QwE1nLXh0OLsDAnyO+Zg1IJ+/bW6YS8NvqCsNx48zR\nJwXvTvuGNl9YJZzl0yTEYnX3n5MivfiBOaGIUDSpngphDenHrGoWaQT4cPt8\nlQCwUx5fJf2DwdazLa88atPZPWpfgLEBRrr4XgfRDd23T/3AWjM3vuGvx1Ef\nG87H\r\n=M8/d\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB9BUhpdKcQrrZX3U0o6KnTScFtJW4KUvJggqflNMq5rAiAXBT2HCV9vtWII0HfkbX+EpThflyNSnngEWLbg2LoHsA=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.4.0_1571993863939_0.19667025954877526"},"_hasShrinkwrap":false},"9.4.1-alpha-1":{"name":"micro-kit-atlas","version":"9.4.1-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.4","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.11.7","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.556.0","bluebird":"^3.7.1","body-parser":"^1.19.0","chai-match-pattern":"^1.1.0","class-transformer":"^0.2.3","class-validator":"^0.10.2","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.5","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^2.0.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"45da6b1ce021c7a1b407c09aed57f169516eb755","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params } from 'micro-kit-atlas'\n    import { IsString, IsOptional, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @IsOptional() name?: string\n      @IsString() @IsUrl() @IsOptional() picture?: string\n      @IsString() @IsEmail() @IsOptional() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nObfuscator\n-------------\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.4.1-alpha-1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-rToiFGZRGCl/dmTV64s/aklAOSvcXd0djGWUO0bhuBJbOvT/hlaUQdnuE9thH0hQcWeh6MQDHyFCv7hbTkHPEA==","shasum":"c9e48e33a2202e33ca98465c5054dc17529f3294","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.4.1-alpha-1.tgz","fileCount":117,"unpackedSize":296369,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdtcXUCRA9TVsSAnZWagAAa90P/0JcMnf/D6A64/MNcfHh\n0D0+TMWk9IzFvYdtcOAPDBqtauF5/RuJb7MMgMj0XipYeElmHkE4b62wwWay\nfB/6O62oowCKXA0ksT6zufSJMUUOVmwX4McZA8ODv8ESlcjcvEcRMyd+0CPc\nzwbb31IrTvG9SpdLnMNHMfNRNh0UFhXBe+dTJlwkVfeaGs12H/SgL2YoSPE6\nB32vwAUmXgMX9pymeZUVu+/bpX//4WetiG2DPlfmWLiYL/HVw7MXnnLxBYDJ\nbXFZVutrrSPHfJmAL/F60xIcZCSW30uJMppS2bW+mRuLVPvPQup4MuzqWgix\ndLRkWt9J7lP8sngc0CN6p8dVq+r8zRf3+Dxj3Rf/XKJoeJ8YobYngG5KbRZ4\n+StPEJbxQdvIN7qopQqFgXrTbqCabKYGoFT+dVZXI3JySDjuTaYP0jg+8n++\nr7hZ2+JIHAzhXEEsWO6j8S3uC9EyWhGeX26S3IG6WOIrpv65PtMCR7++eOR1\nTSn65MBvzHzqqEZe42P/qqGjp2rh/O4Xic0A+7WeaGyoO8xkXOszQDOWqwIO\nlGqlGd/5dyAbiZB+Flur5m+9OvLrgfn6NTILKZAkY5U858GPR7n0jVCoe7hC\nD3EGj8UqdgWSPICaZKIKKPBbOnEqHStdq+ZUBvEKgUPp86EuNF9CklvUHAll\nsk/n\r\n=W1lq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDPs7fhRuk7J3Hp136MX8aYkyvxj46GwsgR4ELAMLlKIQIgNH5rNFH+zeLND1wYBxDUnjRy+jfEJDxvFLksMIM7rGQ="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.4.1-alpha-1_1572193748164_0.1766646550097133"},"_hasShrinkwrap":false},"9.4.1":{"name":"micro-kit-atlas","version":"9.4.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib && npm run build:types","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.3","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^6.1.1","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.11.1","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.5","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-exclude":"^2.0.2","chai-shallow-deep-equal":"^1.4.6","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.12","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@gritcode/routing-controllers":"^0.7.9","aws-sdk":"^2.553.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-validator":"^0.10.2","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.4","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.0","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^1.7.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"cd8f3b67f3d29383ed5bd8aec6763f9fdf62afca","_id":"micro-kit-atlas@9.4.1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-voENokkbzGlRa1BAhKDHd+ntqlDvhKg6n9Ih6rswlccaZ7MlnlWTdXjf+HV1UCUeN+df0E1FvAu0WiQlloc0Eg==","shasum":"562af2af8141ff68fbb2ddde850319dd80da7a67","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.4.1.tgz","fileCount":115,"unpackedSize":295945,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJduYFwCRA9TVsSAnZWagAA0qYQAJ7JJ+giROoyUQ+aQxHS\nZGe0XUa3oRrQxTfRqBiHKOu2toBVBdF5q1ONHEizpVsJ+tifqjrQW/lmLsI2\nGIQo3A/9WiRXnwABre6CnLZZ1qvHwE6YRErZosWo61wWUjiOkiWexyZRzmOw\nqF8Gf68hD4bl2/H/WOmfRKPp6E81AlWt3slvaihIsblZ7Rjf1MmHry7O5vhp\nrK/xx5dsVtoAkA9EXddO+BpOdMz6xG3AkXcfN7OcAwvwUZpHY594rmTtdDgg\nY+2HHmCh8La+jkNP55CyLi4Lgre6w0GHv3yYzOi45P78y3MU2v0I0nTb9/05\nHsqDVX4IIPHOxkGx6N8K9SSHdaotIQM1sUdjx26ka54ATLSQgIfheMYjLLx+\nMd9K2EDkNmuwLsfPjtNoXSU+fkvlDWmV3PUVzYFuh8oMZqi/7rm5X1KcfmLX\nJPf9yYbpPWvLl2U9Pz5tQyMf/JWefFXOpmsqw58A7ulatnEX47R5FoC+yZKy\nrAqAnCbYONjy/eecn/2vrs9hahTy12bwpObQasP/rCB+pGzAukEfi4EGw+T/\nfA0GUDKtzX3tQ5Z+0ff64XwEald3X8jAAfFECSWKWasCC8nnYFXlX6ZCYK1T\nAUtQbwqXmerZErNPAsh1IyPMX7GCzfa68VjMlnq+LrxNhJKBzamF4O5w/+yu\noe5n\r\n=70oJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAFt/4YVEKucHbMokCK8QuhiT6wg6FdLcOcbV5pK6OJpAiEA/c7P+/nLwIykiA0/xkV+g8ahlvp2fBfvK3CRrgvrMw0="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.4.1_1572438383926_0.32138032407514183"},"_hasShrinkwrap":false},"9.5.0":{"name":"micro-kit-atlas","version":"9.5.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.4","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.12.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.6","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.560.0","bluebird":"^3.7.1","body-parser":"^1.19.0","chai-match-pattern":"^1.1.0","class-transformer":"^0.2.3","class-validator":"^0.10.2","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.5","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^2.0.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"ed650143bb576a8423af7b0ccc67a4938f6972ab","_id":"micro-kit-atlas@9.5.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-8R7SINNi4OcDLU01SOZoaqniWy++bqEGqL6oyvmo4rNRqbz9yJuy2E+mIWQWBc4haPvKEZu66HZ8npkVy/e2BQ==","shasum":"6f38472c8ff7964b0fd71c436113a109443a35b9","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.5.0.tgz","fileCount":120,"unpackedSize":308721,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd0rCACRA9TVsSAnZWagAAz4gP/1v+Kb/VLAIdcwUSC36r\nXkzTrRrhdB7t7yD9cSbK0GLBitUUVRLitcZxHMKiBPG8jkNWsdSysM+2bYbf\nAZs4pcY3orfeIPpP0qZY/JvrgkIW2dtdzzzb4S3zxmlfr2d35klgWBzkkdJj\n8f8681u6VoA4jMYdbwXJukschzbexCPZWNgrja42zRnsrqlQPqomaA/wmSoH\nAMWRUTg81ztklrJQbRio1qju9yYxCom/UKcCwJu1HhV05I82U8MZKTLX1B3W\nKxisUYIgnj/HH3yXonLY8wvSdU5KVdK8r+ACel9Paf1RIQ9ecnDlx1X6Jk3p\n0forIuXr9L+eLzM/5Q1D6GKaOVS82ShLacI/cJau1OZJ/2X5vpsaFKXM03xs\nPClqDGGgFOEzwyHNMjuhVeTZQ8cpLU7gMDjW2XU3UH5IW/0RDgm+bEMqGGoZ\nKTS2ivr9H/ULmknR9Tzpj8g7wxh9Cg47cKnezHAplslqdCviu6aEEi2PXaK7\nmzqnlfOBsSiZcMihhL7JAFVC9btmFEAOeyZMoZCpwoZGt3RJdNt/G16YHpZB\nISEct0OdYzfBMQbPemV1oqxkqlHlIK7F+l5q6Yv/NOlqnxQvVZO2Rc6lMxyf\ncpVjUEF67w4SZIWegyjEmOnLtco6JGaE7jKy49itCHLN1nw4KLXE+747Cdte\nnG5K\r\n=KVQa\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBNBPm2LIMgDgRWKWlPpgrVsqA0m8O9x6s9Tek9+RIVwAiEAy/9mPCQJ3JGUqPIl/0w6RnONiZN+Tbl45ZkG9syij74="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.5.0_1574088832129_0.4051988221291867"},"_hasShrinkwrap":false},"9.5.1":{"name":"micro-kit-atlas","version":"9.5.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.4","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.12.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.6","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.560.0","bluebird":"^3.7.1","body-parser":"^1.19.0","chai-match-pattern":"^1.1.0","class-transformer":"^0.2.3","class-validator":"^0.10.2","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.5","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^2.0.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"2f44f8bf0dfc32eadb0181884828b3ad74a5ca78","_id":"micro-kit-atlas@9.5.1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-i9vU33lZSJLjmyCt3lz1WcT/yAn84GQQCAw/sxd9kopZ6jasHvAPctN/lUOyomoFLM2G3+WG3aIKJuC4od1aPA==","shasum":"80efddf5025baedb77da429d639a6e77790d9940","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.5.1.tgz","fileCount":120,"unpackedSize":319767,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd0+8KCRA9TVsSAnZWagAAka8P/0vDDq2lV627Tc1Fpt0N\neHskiga4cNsZD9HYuCfgAEd8wDvCPOgrsb2WQqkkS2qjjzp+6zShJcLLsNcx\nwYTsLC5haTtsmjCgKEdgCvHtNRtU3SPSLxEp8+kUFS0xV2R+bqKAec1eBk8q\nO8onCtUhipv9Y3Ot9JN8+4hqH+B4S6kkMvh375ARiqvrxUGa9IPUFMGhKoL2\nKa8COo6P9KmRhHt3JN7yVxbh6v1qCOAq/Z3jq8g9/MpRlju4lHitaY6RNl5i\nk2y+q37+qrZICkFOsEuDoQc5L5YGQmtnlIXeSg8O5huIf2vzT5MoSPXKFklO\nTf/LmDZ0YM1YePwUhDxwPJdD3S1KKzpzz69nbEt1T4C9oCy8bXAQWMv9CMJT\nvHExq5V1Zwj7uKCUyKiixXfDBWLmnkZ/bqg/EdIVieJKSPrTAADYCZZClti6\ncntAdeBO9EsaPUcKvzeY0SURwe8yAWErCgizB2m6ON7shIxKqOULpnVe2ENu\nPrNCfslUqsULTvdxiEUggasfzOaCiwcyZaKIVdgm8LxufpLDLSUc0rXhjZoP\nzv/jxHgF0VZjyidx6qF1N6dOttjgDD4Oqmto/8mk40LEimFJWhSfHB6gYeVO\nDVGeX/NHYdPDVZSI2jx3lVOSbfS7BHnv7DLStWNxwlSDvKAsuWkrPyrICbyb\nGSOt\r\n=Wa0V\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDIZlmMmKvAfxktwsi4eK8ohdhL0g2yX13gA0yf5mRO+wIgRIN/iSxbleNh8u/moZWzvZ6ZS2FAXJl41Qy8WSOJy4w="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.5.1_1574170378079_0.985590198327351"},"_hasShrinkwrap":false},"9.5.2":{"name":"micro-kit-atlas","version":"9.5.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.4","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.12.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.6","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.560.0","bluebird":"^3.7.1","body-parser":"^1.19.0","chai-match-pattern":"^1.1.0","class-transformer":"^0.2.3","class-validator":"^0.10.2","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.5","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^2.0.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"33f2aca6673658e39e99d31a1c48b12a2b9a66f3","_id":"micro-kit-atlas@9.5.2","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-F9iuwcULyNTV3IdoGBRD6b1rrYcvxO1LUi/41ObMbqWPWDboNzoVtvMsWQMqqEUeB85aTQA9qCnBSKspNTakQA==","shasum":"bf9d774ceab73babaee95a2121993b61fc3321de","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.5.2.tgz","fileCount":120,"unpackedSize":319917,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd0/uzCRA9TVsSAnZWagAAwYQP+gOzvVs+N2U5qK86s6tN\nT4j2R9sLaXreMnxvl50jEqWZVqH17cD6vEwVY9yMAuzBkt5jkL8VunG2Eirx\nhbx63VIbYrzLP74xJD5m3qomQE1jz5QrbX7lvHsYgzt1T/Xm9Ji/57x6qDYx\nZ83xommJEbv4Et0LQ8eZDen4kEFiXxOoS/m/uWTg2tUBthRcoBVfYVnZE+XJ\nJ+D110GxsH067gEWycf315hqpX6jIiziQEPWpZe6iQY8cNDtmkIHgsc0djqM\nxE9muD5CI77jzPTlUXLgbqs+RE4gF8qO45g5khXzbXslp7mf1XHzajaOK9XY\nnYiO60ia1OV2eY9IvVZJz11/jPY4s4sbRRgWySV1Ppoj/LR10VGds9Cxolkq\nqjN/E9Waeyna6ZeEpf68JGeML2PFljxf8icjRCJxVGxXqf/XYYxyJvDC8vWW\nodP5YP/4EaGWASuDPciwRzENbHNHvT+fYZBJZNrV9QcZzf/YlvI+V+QPBYDh\nLeZVFYq43nqDrBCellAn7JiJ+yvYVoiEFG66bl9ynpi/uFfzK2P0LO6xayMy\n2uz5pWXGS2+8vyV3hzH8kWNcrLJHu1RS1ucHJYNeqdNhy8au1awuL39z6Ll7\ngMXKq3gSBDpWsABV929NxjbgCR9rqCKg6ooULSUQOBby3Z2OilWFSL2iv9jN\n4E/3\r\n=xJGp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHZ1NWLWCrv/mpokX6j1pr1nzz192NlvvAcFTIN4KJvUAiEAs2Y7eRvZECfVdEAjfXvuqnQLqag276R+4LF4J0jD3gE="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.5.2_1574173618759_0.6155653589110226"},"_hasShrinkwrap":false},"9.5.3":{"name":"micro-kit-atlas","version":"9.5.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.4","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.12.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.6","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.560.0","bluebird":"^3.7.1","body-parser":"^1.19.0","chai-match-pattern":"^1.1.0","class-transformer":"^0.2.3","class-validator":"^0.10.2","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.5","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^2.0.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"60dad61633d3f1f14c49c41cc64b591d2df6fb9c","_id":"micro-kit-atlas@9.5.3","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-gszCkwUPcGAmVxU8EJH+s++aBfVBpXRMDJL1x6TDSBfB/2Lo3f+cl3gwLp1ZP1ESfJAqxDsEjit+bdiHBR+Wdg==","shasum":"4df691a4c905b4d859028630aa6397e5ed404437","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.5.3.tgz","fileCount":120,"unpackedSize":320782,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd1ALkCRA9TVsSAnZWagAAsFQP/Aizsm8Uw7VOqDPbd5OT\n9VAUH8kiVnJ7GlJOnLmJk6Q5z+OaNmw6e+Y4ek+03m//Xkq2F0Y30qQ4UmKR\nmxysFu+8WJxKor62twVRmYIgNl9rDRH+zFZsAcjX3r+atzmviyevhISIDLPB\nur57AWYhEuAH0XY0UaM9fAZcxKoLj5TOyfGTchhfU+px++/FCd6yOh9WGHKF\nxtnpv0fRDmEfCn98O64JWDjJQcjOn2rrSo3DHa2tXvjIyXaiSDyIGr5Rt/y3\nplElNkoKfp7LXaJmCgoXUOFEz0Ic01SdaweM8wcSqQvn5pMkTyCxx/R7JCNS\nkZlyfCLdC8tZ3Q5lKfWUeNsHFodrpE0MHKXsQKFRJ5z4mgx6Rs/E1cygAvtk\n12fMXIl/uMx6bCN3+Rmaah/xWp2ZqOyNy62AyYmstszXBIHZcW3Msno/pqNF\ncvPI59f6z5JJWSYWkgZ3XGO1BBR0g9xSSyYtNXuiaMN6kkk7t7qIqs4FlwH+\n2m5dSKEILtaEd5ZHUXA5/tcOAXpcejmstMRLHIDSb33pU/oz1yeJihvkLZBw\nXM7hmZVA+CdiUh/X81guJ7HgsQ4jGohHSSdt6ghY8Z30AshuODfnEvCWuxIx\n0mBdvJ0fE5Lg0RP0O1eCcjOezs7yUcFMKIg5iFwpH1S6Cp0ju6sAFzCTtoik\nn7Y4\r\n=Mh7N\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICTMQMG5zSFImdG1itxzlVCOkZO4n24OPl/5jzlj2oXCAiEA+swv5eAG9nYDUQSO5eb+b04OwxVtmQjqs2FsOW61xRI="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.5.3_1574175459631_0.7532566329887709"},"_hasShrinkwrap":false},"9.5.4":{"name":"micro-kit-atlas","version":"9.5.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.4","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.12.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.6","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.560.0","bluebird":"^3.7.1","body-parser":"^1.19.0","chai-match-pattern":"^1.1.0","class-transformer":"^0.2.3","class-validator":"^0.10.2","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.5","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^2.0.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"e7f7ffa17389f148e12a73128e9aacc37a94662e","_id":"micro-kit-atlas@9.5.4","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-NZSbAoyZEr6PwLBXVptGTZioaxnnlB8WAh3n8wRxgHk59lWY0AiuKtAeEHXM0qGBw5+qGx90lS1dWlstgC6ArA==","shasum":"8c1939b5d5b7dd6b4fe7711f0e2a3d8c53c93cee","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.5.4.tgz","fileCount":120,"unpackedSize":320741,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd1WrgCRA9TVsSAnZWagAAQ4UP/0+nPB82F0Y34hFRX0R1\nRL2FGXiCEcpzwizI/MipIUb0IdusFv7hlfqgfOukjnoiafI1YI9KqGBXvfCz\nsZcMKfZvFJBkF927lSlcJvt6CW/0yMEsRSZw3ahqVYJxJjCLENBKjZsXDhZn\nCoDBzufAs65eNW3YmXkkrnEZuwLXMb/VvSasrtLVgjxbMHMHuNNckvHnC7xK\nqx7Exm77kTUSly2z/zHXN7zb4CQ96Cgsdu/rEPU3IN8ckuB+Z/+EirqW8+oL\n+D5DpyJzuI6UHtcfFeyMdJ7saOpXbZYiyfX/+Qj0J1CBknMILKZS5M3S2kW4\nXKHXaenEpjYh9fZBoORdgdbTdfY+FRj442y7FbzI/qTLuiIFbqR7gbAFtYrO\n3TpjDKFkXBMBRdFxShXM8pjjyZx4ZGItevLly/bcxDjvZmR0Q8UR0gWVZx+Q\n+4Ssk9Z60t37DbtI4BsHjJ095mRvI+y5dp4g920f1KhNx4hF/7qOg+1qxriz\n1Kb21Cz3mML7yNN9WIRvWCnXDgKZc5ZAPrZ/9LNKHeE9pBa6TPielPMrSkPF\nHISnjWnJo4abphxBmu4FBza9q6zbKDLNpqayA7mZaZJizxaGBWkq0yx6ROr+\nB4mrsomgczj1HbswhY0jiOTTjx1966s3p3+WBlaptiqXeQ0kNSLBe9GffdIx\npckU\r\n=NFfH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDXGEgt450FVeECI7q4b4m5XJ3apNnq6Emw1ETN75EbnQIhAKdsj1R3cRZ+G7pkO9gXXpqJTDMHkjm1rgaSLRzAAmZy"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.5.4_1574267616107_0.8783856911873014"},"_hasShrinkwrap":false},"9.6.0":{"name":"micro-kit-atlas","version":"9.6.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.4","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.12.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.6","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.560.0","bluebird":"^3.7.1","body-parser":"^1.19.0","chai-match-pattern":"^1.1.0","class-transformer":"^0.2.3","class-validator":"^0.10.2","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.5","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^2.0.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"0de0b74b688e316ec8893d29b40eb72c728cda93","_id":"micro-kit-atlas@9.6.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-eGiNKqzEQYMEnCnwQD3xRLvQ8NTMNw0dC6Qb2WAnylXnI+xcqMpdIfNepZOvdTAKOwcsg9qq7dG77WAE7Bm5yw==","shasum":"02a21113e0bb42e0689c57625356a1d0f7d98787","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.0.tgz","fileCount":120,"unpackedSize":343894,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd3UoYCRA9TVsSAnZWagAAekEP/R1v/YNEtPoh2aVp1fi9\nEprch0lLd9hP5w4gAt1O84kGS/fGn1mv5r8jmD8+8SFkC/d5gRMePEiqzCWu\nBxFNLpTBRdrm8tpQSJLdKrv1Sngji6n/rXAG7kwBh+nEZY7Y8qNti44vWuBu\nzf24uuBCSdveZa4iBvxrAb9q7CJJuQAHWtCI1FVFFWnmO40agOv2iE5fv7EQ\nLGK2sYkj/ov45wTQMOeg7bwwx6R5WA8//WhdBzXpAtrWpYqmR1uJsKpEpPK4\nF8eeMyPMrf+T5tfRqN1uhoRLdRv1W3gTdmqtGK1Rh7Y/jVlI97vF7VWQd6e1\n3PJiL3nR9LM4Fypma1steXmgJS2NSd7VssEoosxVsWJK11cTIuTga/WvbC/q\nJG1XK9XxNS+WzDfoxxLQKZV58qVXOQUdo0ruu+/FFC4ZZeIMGVbX5EAdYgwK\nul3bm/sMbNDWmCfH2AROyHpQ7g6I38sRM3pFXvjFWBPkYRMkw6/JavyJuGnL\n/fJT+5ijD7Szuv397O+6Y0+MiRUqw/JqytqaSMTvUJJFPbZ1xIfQn14fVqiU\nBV1fgU4ih7W9OqzLfW359g+ap01G8VgEBjEuiCZT/UxcMprxmCLV9++ln+Ic\nsuWoXFiMNN86X47vVipjnjUy8zlVHg3Bx6RHOSNSL8dOr7DjK1lA2cy8fkU5\nM+uA\r\n=UFPZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDNxDnJVAdoGypra7onoOE/UOZcJx50TaFE4W1WFLW4ngIhANTC0Ja6qqqdF5I0vN9Ox7ycJiHUEcncaPxMlpRoSh+S"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.0_1574783511868_0.44811365570291417"},"_hasShrinkwrap":false},"9.6.1":{"name":"micro-kit-atlas","version":"9.6.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.4","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.12.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.6","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.560.0","bluebird":"^3.7.1","body-parser":"^1.19.0","chai-match-pattern":"^1.1.0","class-transformer":"^0.2.3","class-validator":"^0.10.2","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.5","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^2.0.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"23482b498cf635e25d185ca4911c4f08d6f7ef7b","_id":"micro-kit-atlas@9.6.1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-oEqBm/EJog1HI3Ei9dfaftZY6tWW7dCn1GGoHxifLkhyI+lUMSIsPGgNunb2Jo9odAiz1KJNMi5T2xeBGTlfgA==","shasum":"9b7767716bd7e2e897be1642e087d61dd6d8984c","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.1.tgz","fileCount":120,"unpackedSize":347667,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd4DclCRA9TVsSAnZWagAAIqIP/2rGYKfR8v1rTTeVKE76\niUrXtCgyG8pGeViOo9CCHqh5H2yMjv9+bidW2s77HljobPkjF0yJ4FLy7q1v\n50Qz4KLwSNWc1HMjibt76u15JrtrM526cMpfxGUJv9qFwmm9dBcfs959IFCC\nnNdzwk5W/aWMX9s0oEbz97rmPFFjq0gL7nDfiNpqRjQC63eaLuMaPukLmO0P\nmYj9ZITllKzFQPuFdg5HL3NJv0IdMr+hYoXn6NHadVTO0aEzWfzBGL+ElgSA\nubd0tgnIT3Cgw99ihVZcdMmw6GUKsW9B1qWyX4ar8teG7eVqrgA5wd7FMqsQ\nj0nBjUkjN3kZ3BVv2EdCUDvQHrjpd+ITqWIhTEi/n8+JbW5NbUnvtRoSUtHJ\nFJ79G3fpOKxomzxGu3Fix9hqkxvMH7NJwj4ZBpWhRU/ISAEL9G9sTFRo/BNq\n1BsHF0YQqYL2JuARdmhQc+XN/IdpWh0L4fImA1U70i28fFtG4hCQRkdRFbVz\ncFMp7Ud6lm8MwcCz38d6QQFgQH2AJZQnbIUQJ78w5CFHpYEGB2zrdYYBMFkP\nbCGK3ihERFiC2PK/C6YlRgaUWuI3dBECnKdlCnE0yhvSSy4ZBq1P5OMfBcDL\nLuYIly9FHPY11jUtp1auGcy8ZusZaxGZ80B8IGvgenydD+1ywSvZLH7qXdNw\ncIQJ\r\n=kFSO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBxuWIhnlUcW0UnY1IY1ReCcjMavFxiCHeE6sUA2tc3gAiEA13bLY4APHBcl9oqJvAeNS2ryZBZN8Zjs5L82LxlTglU="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.1_1574975269140_0.027304923064471742"},"_hasShrinkwrap":false},"9.6.2":{"name":"micro-kit-atlas","version":"9.6.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.4","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.35","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.12.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.6","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^8.0.1","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.560.0","bluebird":"^3.7.1","body-parser":"^1.19.0","chai-match-pattern":"^1.1.0","class-transformer":"^0.2.3","class-validator":"^0.10.2","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.15.5","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^2.0.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"4bda47a8a5e445decba96c9da0e56caebb04ec90","_id":"micro-kit-atlas@9.6.2","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-n33LR94lxdrRjz1WAEo4tx/3zby3qiPTwoVGx1VT6zVg9iCAR2mmKjkCBzXHbtgcHK7k9RLzhGb9Cob0tg8zJQ==","shasum":"32589f3c882685db61ac345b959163c7c8ff158b","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.2.tgz","fileCount":120,"unpackedSize":349476,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd4NQoCRA9TVsSAnZWagAApD0P/A7nbtTyaOcfHb1bMmGE\nq2UUrYut+gEuNj+plO/eMIQy6Lv7w639dIpAkNYMcuzS2dEXf8py3yK5GCYn\nkjdOsxCRaI5i8Z8T8RMPQsNc9LWbONyl3SqdwXIjx3m1D0aofIGPTxqhr+ub\nBJ+9nGZ0m1wW4wmfNudALMP2vfZ45bQl/olFmSxpT+QTFg8WedZIT0xI23h6\nHxBsGx52F47YvwBQ5kGGMefS6laQifyWknArkbbbPkMu3rSm8lepQqlTJmcK\nqIyiP+Kphg00r7mYpXs8L96B45UCy6XltQHtO3LIHsyIN2cDdiBWI620ACrd\nxxqUqhUsDYyL5H4LgyUxXScXMducfG2TCrTwUuNeXpBzJ5VnGo8tQjnVFTtn\ny3tbrh6Le8lfpnE2cK2yVFokHeZpJVfYlmwOMXTELeAVbmgKjzbOt4ofGeCF\nPZAnXsr860tMGtam5ODswVfhLQuKAlkRqRXqwe4n3/dKJQi++o8fHwlklNcl\ndZE6yhETBCelMwJ4tRqKbjzGyBpgJh5L3i3+45smpp3pUJXyZ+LfaBiIkp0G\nKmaM5q/Nu17bwhLlvvDrJua2O10M/Fey9PwaLVcnNFo618UrREsHehMCaPuH\nqxlIGI6qR5wC3ip8V43AFElj2R8mGp2gmsLhP16QZo/e7Qk14hjrMwkM0rzZ\nAItX\r\n=mMFj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGwd+4fFWVVza6fybSXP7tVjURjNvCPA2PHegE8f6GH2AiEA+XsVO5Ep2ny0umhaEA5z1a3aqvL6NEZL/V+ggXtuxRE="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.2_1575015463363_0.4903256856215248"},"_hasShrinkwrap":false},"9.6.3":{"name":"micro-kit-atlas","version":"9.6.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.4","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.12.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.6","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.560.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.16.2","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^2.0.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"bcd894c8ff57d64c96447a049bb81148956710fe","_id":"micro-kit-atlas@9.6.3","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-0WkiO9pl9+itSTNlU+Qr7q1I2EaSPHx5D+K/7IxWZCu4I2p89a5txQby1Y7pbx45DC8uqFhdyyGm+gyEKG+CIw==","shasum":"9e5a9f23ef10277f0fea4cd79803c1906909384a","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.3.tgz","fileCount":120,"unpackedSize":349526,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd6Q2GCRA9TVsSAnZWagAA/MkP/3eSmamHZVAYlIpF9TkB\nF/bUnVTiE1e/51F7ZQ1A37/po1u9YSXFU5W85o8wquinR+r9MgkPLI0il06o\nqPzWUSLopIZ53le8cQ26y+fLNtpNNx+6Bcb1fn2N1n9URrFhttk0xsYVN1+v\n061YMCJDSBE6xFWKEe9IerppmuVprwWuArHylANEh99KBHO0qO5aBZyeneVP\n+ucDFXGF0yNFG7LCaRbYD4JRWKeaPo+T16u8Rt6UCbYgsQlvAI4RhqUAwiZF\nuwZ1nRpn2o0Ti4sBCiwnYx0SsQZefCOMwBymoD2AQ9gTWS74QMoRqwz4IUSz\n4VBHd/DCVSmOd81YTJGSwtEAM4M5TPrZ6tVYc5YIMnO1dFsqo+hZ/JHuOmvY\n+XuXqpYPTCz66or64aK05PRykjFsxvZuypcMvidoWRf/7xvd8MVTFplMS43P\nsZ0f7xrBuS/HME5WfSyWFU3xDQnbLF6xzqCHxjj80q+BDyla5pLXfCMSUdLi\nJjZ0UX99zzKcbDMmbKfxa+9ExPC32vYW5w8Sfq5H+kwa7813OIrmJ+l2eduQ\nTE1MIMcj0shNmb7/6UA/Wzye9KEHO9cgQM/YikEeVG4NyY2XkXBLkR8K9fVm\ne6jBSNWjZ39bH0Ga4bfwsImo7g0hNbvIovEwfV8B8tHN/9kmh/SvZiZorYJE\nAnYA\r\n=/eHE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQChcIsPH+qgbN+4pj5oncKOHEBb44tgbZyNPkyLI7VHfAIgWIajhCW/VQvoCGdtqk3flyazTIQmKt0HMqdDjxrCZtw="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.3_1575554438244_0.10421400395364833"},"_hasShrinkwrap":false},"9.6.4-alpha-2":{"name":"micro-kit-atlas","version":"9.6.4-alpha-2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.4","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.12.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.6","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.560.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.16.2","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^2.0.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"ab603c1ab57dafe214e010e3c6cbcd8859a504d9","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the null value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.6.4-alpha-2","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-epBrkc7j1ud8BdEXxsSaNORespspQN8MEx5EPMV15Sqc/WBx0PLp/L2/jwKhl15YtT5FW3KOt8TeTp5Z1ETwzg==","shasum":"fef8051d94dd9d6b796378bbb20d14077e0d946f","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.4-alpha-2.tgz","fileCount":123,"unpackedSize":352501,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd7i9WCRA9TVsSAnZWagAAFuUP/3gar0G3pKE8VT3Wot8L\nFp5LBmXatw2Gw7i8OxA/OHxt6kIK8qKLAHlclK5p/X1yn+pQJnIOLDjbAmt/\n3HRw1Ds7eidWKFEXdy1sHaUWNeuwyF/KgIFqg3u2o9ymfisPIEir6N/JjHL+\nTtYC5OQdphdGxnJxGsMPbYR0Bk8sLpEEcRf+xSFdJ5/jcAODmuQwSNwEyYzH\nPcCSFze6axVthSZYM0nMI4EF22PltPNtoaCJXCsSDOuQ0dAg22RFKoVyEBO1\ncupqUTJi0aMifFQo6lP7hR5KtQ/0jRDrhdN3/N1woUhsQO+NQcEcn5bvCxch\nyjmvN5ELOS5XEsYXHrdEufNIsue9lrNTrMtNcpPOzbzarFSF9qKdTiPMeorX\nvo3OumfCvFwYJgEp2Ase/tBSaqrmAyrloE2o4hp/lJsNdMuY45RAcKPL8Efz\nP2wFRQNpqITLoq6sAEjl4RBbqoCg+JHjZWyA050Lq+cWZ06BeXSg5R57raE0\ndNiaU2xkfY5o9gnYo2BNorwejz6dvzPHe6GW28FfsYXb8b81FR6jO66k/eM2\nQL5afwIJjRsn+hAqkRMTkAfQ8uFhRDP9oIqS7Vk8NQCIx9stltUk5euMOiGE\nu8lwmY4SKwaQ+ZMmuU9SvVBzR3DsnrPHG77djJBltFvPhFhmPyzeU95ya2bL\ny5oi\r\n=HXVS\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDp1Ggocrw6MpiPZE8STmIKyq+vqMp47cW9Ggtxu4jxtAiEA9/iemWyUBQUDJ1G8wuDTdqvIPASK3bwW9bxHdOWazLw="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.4-alpha-2_1575890774238_0.46869842828594765"},"_hasShrinkwrap":false},"9.6.4":{"name":"micro-kit-atlas","version":"9.6.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.4","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.12.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.6","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.560.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.16.2","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^2.0.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"db1f40f45b247274139454c5638b1425f946eec8","_id":"micro-kit-atlas@9.6.4","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-go+1jkfGf2sqNOlVnMN+Lx2P0HBF66IJr0mQ1ZzkSLFlN93uDr6vNt5OjYLhQviSY0kPV66A01xgrp80GVjs7Q==","shasum":"c3defb4801cbfd07622b2b174e46d307ea818182","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.4.tgz","fileCount":123,"unpackedSize":352493,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd76NnCRA9TVsSAnZWagAAATIP/A9p/5wplzPw7xIfDA0T\n8itW6bDH4zWf1+hx2FQAJLjVyt0IMkL4mlp1hxNqpU/sfr3IsehJDxHuhTOE\n4fJuEx/UDUbdOt3a/Fl03QKrp3HtcztFqIJqU82qfWVczKjopzDbsYka5w0L\n4s3c7d1GBxlNoPp3VBbxqLP0Rr/sh/wq170WSED9TNlMoApcl/mooBfQlsa4\niPtgM6jLlj9j0YBAVD3YVrdcNVbn1d9Z6G3Swj0O1maLi6KNmZoQFvZpUf/r\nqjGl5DXdVeXALbh0TJNXiwkPCRQOK4PYoaUdDNKUkZdoWnNxkNSPr0ZR5fOH\nmnmqFr95d9cBJ1VhdRj3dLET38dkjOCuh4hT0uKkAEoaeVzXAu6xb41NtVHK\nipmauMbV3+ne1eAz2pXEV0/Y+Zuidi9+IzazGfG0L/QDYAmNCM8cfxs9cUDG\nHexnIknl9SpQqXnowOntdxEu2gaRDzRCdJhxoD3MOSgGIXSKvkaNQCfkl6I3\n0ATtM4XvRnnp85a+zloZTlQIr7UDHTxOLffH22XTb8D24GVa+YxXYfMaP2Zt\nV2hpeYEMkOrOoZhXiS983jn4d5MQLLG/+qJz3l0fuHgh0Y0ufWoSnZcg09kU\nlFPfGMTeSUQD98n8f5QS4oeGzSVztTFKnZMFsy29sIpp43jC8XJtLovG5SH0\nigU/\r\n=wugY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBDscXw2OFH6vucEgWJZZ++cDUbuuTX209SnrSisfcCuAiBhJQ+p8aUXc9Rac3HF5OKLd0YY5e1jvX5lSHGArqzNjA=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.4_1575986023063_0.27324815609363906"},"_hasShrinkwrap":false},"9.6.5":{"name":"micro-kit-atlas","version":"9.6.5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.4","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.0.18","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^12.12.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.0","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.6","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^5.2.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^6.2.1","nyc":"^14.1.1","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^7.5.0","sinon-chai":"3.3.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.6.4","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.560.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.16.2","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.4.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.17.1","mysql2":"^2.0.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.3.3"},"gitHead":"b9df4c40b3481cadaddd50ffd63d52e4069af50d","_id":"micro-kit-atlas@9.6.5","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-SnW9FEI+fl/qRlsbUdKvmyjynhh1kMXa8c96gqWm3jbCn7yI8KLvdrYm0sCZ0FwL65qPlw3FkG7HqJ+jdVIbNg==","shasum":"4009e7456f5ba3c01e122eca7e555e301f056f75","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.5.tgz","fileCount":123,"unpackedSize":352691,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd+yxOCRA9TVsSAnZWagAAhMoQAJGg1fuI4/YQ1HJG4WRN\nrRHYAxBz/nxKGmndi3NkMI2Vyfqww6+zZnTUSYdYqC5GhrjgqzKzfHiEDvUO\nVZ71bKkgl8hJfUBDoQEu7Hza5s5jWJhHQzAYF001bdor+0x5LzI2hxaZsid8\nVHUv/JZ+Rl6Jy20k7PlskTDeS2SmLG1MYQXiykib2lYJR52v+EAsF8C3x8Bi\nawkCCzRSkh3G6ZoRuQDWiilhl+BhC1N/sKfrZJ9xdSsDpLQ4xRJMv5VZSa1U\nruKrG28rFMZQG6ofwDECofZ5ZoAOlAHojmoklVQGRfFqsKHq35sfjV5pMMGm\n0d/CAwv7XuysRfHPxidYs50cijfTW08Lay2JDI5tOcYMD8MaKGVajlnRlXpg\ntZdcKHKTWy/5z5Z0I/td6GzAZ9LvsTmQytgfsdz9YS1rkclGDdztHD3QDiq6\n5YuDSw4KUgjn+X1MgoruEqxfR87C3ES/YY/1IbsArQrf1bI5APcAIwuGXJIm\nl1lUQn8yOfooOhPXWIvs/rFvI3gQGfci4SNi/fQml1JFGYsCW9Z9HD9L605L\nh8SnMjMMTzLx2w+0RxmK3HuOFca0GfC2wM2Wt9lfNPBr7mMt3bmBEBp6fWbK\nrLgayzA+VS/z+CbBJL78x0wmv5+KU9uBoLD72OIsvCgb+Rn0CFWfMOpgH4G3\n86Kk\r\n=3OQF\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAz4dycLccIFpO9tbTcTSrApdOjXeu7U3hNazPt6Z2L/AiBxnzrkHgfLdJKBWHDW+s9ekfqT8pVi3/+gc4USvtrtAw=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.5_1576741966279_0.05462436281982197"},"_hasShrinkwrap":false},"9.6.6":{"name":"micro-kit-atlas","version":"9.6.6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.7","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.4","@types/js-yaml":"^3.12.1","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^5.2.7","@types/node":"^13.5.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.6","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^6.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.0","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.0","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.609.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.16.3","decamelize":"^3.2.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","jaeger-client":"^3.17.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0"},"gitHead":"8aec60e302bd350eb6feb8a6d92e311be55aa682","_id":"micro-kit-atlas@9.6.6","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-sAu9VSL3N6GrVUbNlRsTx0TWwW+KeRYob2RpXMBoHv4J6QTRTm84OC97jlu6HeyCtXD+c9Cblw+OBgjE9C6lWw==","shasum":"fe88dca4f6835b22c4db3493d9fc6fb6c0be44fe","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.6.tgz","fileCount":123,"unpackedSize":352767,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeKv3ECRA9TVsSAnZWagAAC10P/0vE2olmLicitdtJYcjA\nN4BxqGoZ8R1qj0uxKRUzsaW4xjHFlFYuz0orpOjOXm1VnDUbUMLekENdq0to\n1OUPphEGPtGVn5CunJlXIz2kO3V6M2In12q8nMj7IK1dVlEVs/dlMv1b+gQG\nd/j9OF0kXuI8l+D7YCfVkxNQode+L7+WkGIMKT1agmxBQ6RreALFFWlkS2MR\nBhsj0p5y8OmZ1q3dhWwW3Pi2zhHvkW7A6+XLPo8CLxeGIxfubYqcxnXLc3vn\nm6FfSuycxyqgItWRgmlbMQwIIqIYb+eXj84zROjThAldd1TmI6s2qZq/0MoH\nQR3swFBUeNe24fQ6w8/GGwkaSygydbtuZnh8Bke9M/UdKBSxq+eVsqtSJPvO\n+N3R2QTYRFHv4hlgmWeOPGGBswbs0mB5ROvbLd9ssHYot1x30GEfHfpl1yxg\nW6kIu1FOravKj0HBIcRUdnloVcuaTPJ4gnYDAj03CljYOCBNJx7sSo6p5pqQ\nt3iK4QVRq15jt4YANG2sOPLUYg+nkXDNs0b1Teu9ma17sp97Zc5Mm2yqsc85\nFEEaHa8JohmgVhkV40C+EGRxv9EavDDKdIcWlBFXmHhmiXH4oRys6/TvPILX\n83I/UuY7Ryp4zSvvfjYGl4HFdItw6PAzQIVDtzpKWAM5m2WuCCRWbSmkMhb7\nUH3T\r\n=TJI6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFvHVQ+g/HsS9JArqGBUzZDesqFeLa9uhF8AS+oV7494AiASA3uSmrLHRBnEj//g+XHc9KhjexgH4hoP5xZgbJeRww=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.6_1579875780378_0.13294885778391152"},"_hasShrinkwrap":false},"9.6.7-alpha-1":{"name":"micro-kit-atlas","version":"9.6.7-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0"},"gitHead":"9f894355aa8ce089cad3b9769302a4d5a3dbdfd5","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the null value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.6.7-alpha-1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-NjjILf3/XY4BBHjj5FVAOabldjtHnFvyz27tqKmxN6TG/+E5F/2HPasJomV9S393aZYJNIwqnJrPF0itLi1yXg==","shasum":"1099749067358176d9990ccdaa3ab4e88c11b2b5","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.7-alpha-1.tgz","fileCount":120,"unpackedSize":345452,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeOuiICRA9TVsSAnZWagAArN4QAJ1DGzoRXgh2sNuNSQoL\nfPZjA0Upp0pEQvC4sz43OPEYi6vyXPtJfPJMnMyqY/eQ8z6VDNBCg0GFArSN\nJrKgh4srgMgZ4ZEFPikvnxsuT59ullwAYrENYck3zIYK+GP5NzGyuc1xjNVv\nZzjf24HOlyBjhVeTmX28ADxtSezZAYmoJLsXgBwkifyvTaVH3Fe0KdPxwoVj\n9UCqp3HZYEET0YTbp9AESj4M72lSA6ovd1e2QTCrN59UcRT/FWrLOHICmOgR\nXfwv5g1LJrD3rKfNIBifev4frRdNg8gm+G0KRbZbbgVxVc24ZKOFstHKp4RA\n1M0ru1jQnYAjc0b1dRNh72izjm8GiY4j/ELTL3upR52Dug20FFfQ0+ZNh8W5\nO6xLK67qtdDE/+UPmpwM5flKnXz1+gdnaID4pnzsbxfmakfYLZcf8DtzszYV\nHhHuLGsxO9PQ86hZ1nIhZfGB6YLqX0A7GKGpPtSNf4FOMjTIY3LxUkuSv87k\nr0gM2rqlNGreHPi643S8fvw2zGBCCBmaFBxCkvnsw/iF8fgTEtGLYf4G9vlg\niw0W1IQ2v5OBcogMSK+htGuk9BMF2BXSv5Oj3/oLQswlhU6FNPQt5p9bb8GJ\n5YJ6BNHBnvV5SwhksRE6ZRz1i+xuCUYfZv2uMDZiPr7FBmgPwk/a2mC/98iX\noCbP\r\n=5kfT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBJ7l+cGmcFX158htovDC0D1cYYLbA7kuj6t34HQcHlTAiEAkkj5PzwkkF2M0HPtCz5To8MFpytVIbLL+P2OTFj9IMk="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.7-alpha-1_1580918920022_0.3424842459254285"},"_hasShrinkwrap":false},"9.6.7-alpha-3":{"name":"micro-kit-atlas","version":"9.6.7-alpha-3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"4044b743932d2c5bfde61c304b42a96287a62b5b","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the null value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.6.7-alpha-3","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-3h+mhTvPQE/Xzur3Gf5kcdD66LzG8VKtsM767Rf9jvfALfEk9V3Wi7ySFGgtAoOjayNsvXuvvg/dBqXr3kU3Uw==","shasum":"7d5033c1a7e2abd5e1f03030f3d0c12a23e2c9d1","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.7-alpha-3.tgz","fileCount":120,"unpackedSize":346181,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJePUNaCRA9TVsSAnZWagAAP3EP/iMkAMwX31JE/3X3KNvm\n3Iw4vB5mrFgA9fNuN6HbC51xhDPHpKyq7HmmXrMwPan4Xu4zH1hgSzpXNdEv\niQPrDgptUFwr6DjWXW+WV37ke4YaSWuRUHkoPLAeBmtQfpoiHCS8LWaCQPvI\nVoqGKAcUoGoYbJwPhdAqQKQVXzFtdt443RvCvRB1P4fWYgk8CKoZ4vVr28sy\nqHgTYMHSmYm/64chIKnEyCt0kbRhLDSDL1eyKEpswdqImFOA75GzLHWStoy/\neu8wkCoc1IDOPDz089C0w5HiS9NbKtA3X7GJAH0xTvpneHfvbGW0e7eeqxjR\nbmD2jpnNsK9aVbXZfu3gHz15h80+rGka+qeqKGMta7i+9uR92yCM3Qb/rp4e\nIgMnkuyFaTyEHlSFIFiglGLkvwa4HA2u8q1yA/BmGd2NVr09+wdD5ZGFFicl\nORVRrEghckpaAP+FRDl6KrJ2vN7cXA8HYwSGt3BGdYkHhWYzmWmbSr72iUyn\n+rmTdgITqxOrLDG7e5V9loUgcydnjZBPghmvA3cxCOjNBzWQp8SOHSLh7WZR\neL9sOZo/iawa2SpJx2P5xNnLfX4HH1khF8/KLL+eVmiyWUuPy8lSIVyXZy8x\nCrqg3Jxo3G5YEzAfaSl7qwt5KuktR8/7/2gqtBXP0Ce4XWcKg9cd3CEKKPac\nwx2u\r\n=sWT1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDflSx8S+ZnYCCZtr6jgWFUPuwzOg4ZPHAB6I9v8bGJywIgbITYhslPkzSswrm5pNm7Fcdp2NjO4uk2L3UCx2y23X0="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.7-alpha-3_1581073242122_0.13233244303197744"},"_hasShrinkwrap":false},"9.6.7-alpha-4":{"name":"micro-kit-atlas","version":"9.6.7-alpha-4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"6e6135d85cdbae0e929b4679b50de537aed42913","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the null value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.6.7-alpha-4","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-lx3wYnCk1sSMulNBKsnOA6QV62IjXuB6Z/EXdNboiGHejpB+5FgBT4+lVrIN9+16xnFE6zoebwK3spI5M2Sb9A==","shasum":"8e3b63f1354febeb37a01a5284da806900acca3f","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.7-alpha-4.tgz","fileCount":120,"unpackedSize":346631,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJePW3PCRA9TVsSAnZWagAAbtsP/2acGbNZBZmvceOb12vG\nDDATCkX8Yd+H8zln2fjVvaq0bFipweBl5vqIewNk111HwIAngUT9gfrdTx51\nvkClePKM+0r1QU8rIksUO2SGSxOYpwxyoTvmFCvvmf4rV9Ju8K21ZF+bIG0c\nGZ5VwCp9NM+1PxUDTK2F9yG9GpM5GgUrmQUwyMUjYxRL4NkDEApQojGCP7Zo\nr8QNh+hN5aQpjQGd7HYIrXLtg9E0seHKIIhYhDsNkwf0wZpvPsgZXwB4jBGY\n2DTLaalQol8YNlObjwPAQEIBV/CGcMdzsg1WLs0GsabFMrH063xbW5Z9WMJP\nb2vhIxMdjrjohnVaP0W4gWvW7LhRL8dNP3LPhfVEYcN+7PL+L1TCvHGGNQla\nLzGehSmUdUxQZw93Zvaa+5LRcvLAABiEsWQ8ah26KXTH8YwawpNMCY2YwENR\nqQUKk1PnZ4D2Q0RNG6izv9leOqyzmPMMJz9Sr6mRUP50AxuKfETvzI4I6P4j\nCJOPZc1elc/U3voXXMUZKCkbqkfnyGtYRjfqgyYkajhQ0u7AX7XAApzMb3Uf\nGz6uAlpQMYnP57CGh0tHcDeg2cpDeey4HKN6Hw9OfjIxZyjegQmSMcdnpyFh\n+mW3zJfaq8lUdxRiX3YCtZGwdbAo8w5NxDcZ3tR7cqGW7lXCpfyQBURPu24/\no+na\r\n=c1Ql\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCvjZ3dYtKizHrBZKhfe3dXT6ex47ch8XnAG9zWJiLxqgIhANrqi3E/rteZeyRcyBvIOltksXtQuN0A20XdfiBITPKj"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.7-alpha-4_1581084110961_0.43420638015097235"},"_hasShrinkwrap":false},"9.6.7-alpha-5":{"name":"micro-kit-atlas","version":"9.6.7-alpha-5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"d38c6db6776b7d127dfa5f65970bcc4790bf17f8","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the null value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.6.7-alpha-5","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-dnl1Gspexv25nphHxMb3lESfaPgTySGDDkIQoZ5hODSj3VUE+fFXZYgp5elTTgkKVcigaaP4jcInzcMMD4JgoA==","shasum":"44533064c235cf8e3258b312ec279f7d999ae8c7","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.7-alpha-5.tgz","fileCount":120,"unpackedSize":346689,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeQTUKCRA9TVsSAnZWagAA7oAP+wbcK+D0cr0o+3JlL1H5\nzH4zNa7U4q1HmqwHh3JtItlqEVL+L47V8weOftuBs6J1hYP3A+qbiAHZMxvx\nQ+DmXvtPG5F3KY5NE4tw+MwXZG+r5RmtKTGKHzz2BAqVfeBMA9R5zwIb4zQs\nQXNp96Q31qD8RT0fAmkp0paOZBMoqv2ZB/rfInEK7eeZ8Lnpw/w4jrWI3oH/\n1h6LiROgHSz97ujWErA/eze98BP+08a2Mi4QVxjn1B06U2Ew8Ud95YJTcoyt\neC3OP6GdgjNNybKTxVMFKhmxEpPLe8M8Tv3c1KDbaecUvZj/aFeXNr2gqjR9\nys/aO37GQYHH8AUOs7PmNp2tHO8cYnQSCHPIzRlDtgLSkIeVjmn45WMVYNPU\nWsychzX0ejWbHQG9BbhJGVduRor9hGk0Uc4AP+OH+nReUZ18+QlbdqDKcZEV\nBKDjkaVBA66NTGoE8YAZBDAvQMosP9OImuHG1/QB2Uugxe8QJY2OgCdZ4Kwb\nol31is9HRWnCPygb2U8x6MFnRRBWrK/VXAQq4UOkA830GYC1CF5vtIkhe1bl\nZ5CApARz7cnWRkIlWwawNRSfCrdYdaUYieSwDeNzqHEEm+HLaiavfYgfrUep\nnjjH5QUUXkxTW7IiyueWhyE/tJ0pldzx/A9IsoIUJ2pZL9G+ZALpHyc8iGHT\nxcJM\r\n=YP9z\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD8kztZpFozrUnTb6UASVivDH2HuBHA7cJJsh6yaoNv6QIgIykQc8Iz4eJQNS79V32j+uWhHjBnxevNMLlLt7jYgKk="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.7-alpha-5_1581331721754_0.33791602844822677"},"_hasShrinkwrap":false},"8.1.6-alpha-1":{"name":"micro-kit-atlas","version":"8.1.6-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.17.1","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"~3.1.1","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"4bae3fbd6f69386468943678022336cbe41a77c2","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    \n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n    \n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initService()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n    \n#### TODO? \nDescribe init(options) and finalize(app)?\n    \n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Support.\n  - Ajv validation (only for HTTP request parameters).\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n    \nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `host`\n_string_ _optional_\n\n**To be removed.**\n\n#### `serviceName`\n _string_ _optional_\n \n **To be removed.**\n\n#### `service_root_uri`\n_string_ _optional_\n\nThe URI segment that identifies the service, after the versioning and before route part.\n\n`/v1/service_root_uri/route`\n\nIf this parameter is not provided the routes will have empty segment.\n\n`/v1//route`\n\n#### `namespace`\n_string_ _optional_\n\n **To be removed.**\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted. \n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n    \nRouting\n------\nFor apps using Atlas, routing must be initialized between the `atlas.init(options)` and `atlas.finalize(app)`\n \n#### Basic use\nroutes.ts\n```typescript\n    import { router, Router } from 'micro-kit-atlas'\n    \n    export function init () {\n      router.exposed.GET('status', 1, async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n```\napp.ts\n```typescript    \n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    import * as routes from './routes'\n    \n    const options: Lib.Config = {\n      name: 'check_status',\n      service_root_uri: 'check_status',\n    }\n    \n    export async function initApp (): Promise<any> {\n      try {\n        const app = await init(options)\n        routes.init()\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initApp()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n    \nTo see the example in browser open `http://localhost:8080/v1/check_status/status`\n\n\nThe Router in Atlas has three interfaces, _ExposedRouter_, _ProtectedRouter_ and _InternalRouter_, available as `exposed`, `tokenProtected`, and `internal`. Both of them have the same static properties but with different signatures, the exposed router requires a version input while the internal defaults the version to `/internal/`. \n\n#### Exposed\n\n    static GET(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The express `request` is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\n#### Protected\n\n    static GET(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The ProtectedRequest (express `request`, extended with `req.tokenData`) is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\nProtected routes have a middleware check that the request has hit the API with req.tokenData attached. \nThe tokenData must contain the fields `globalid`, `uuid`, `client_id`, `scopes` and `grant_type` to make it past the middleware. A request without tokenData or without these fields will be met with a 401 Unauthorised response.\nAs a result, the controller gets a ProtectedRequest instead of a Request, so you can work with req.tokenData without worry.\n\nExample controller\n```typescript\nrouter.tokenProtected.GET('identities/me/is-dave', 1, exampleProtectedRequest, { schemaConfig: { params: '/IdentityUpdateGetParameters', validator: support.schema.validator }, })\n```\n```typescript\n\nexport async function exampleProtectedRequest (req: Router.ProtectedRequest, res: Router.ResponseHandler): Promise<boolean> {\n  const daves_uuid = '86d7e731-da23-4e2f-951e-81a04665f002'\n  const gid_uuid_in_token = req.tokenData.uuid // Router.ProtectedRequest says req has tokenData and tokenData is of type TokenData\n  return gid_uuid_in_token === daves_uuid\n}\n```\n\n#### Internal\n\n    static GET(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n\nExample:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\nExample with redirect response:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request, h: Router.ResponseHandler): Promise<Router.CustomResponse> => {\n        return h.redirect('https://globalid.net');\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\n\nSupport\n------\n#### Schema Validator for Routing\n\nAtlas offers json schema validation on the router with [Ajv](https://github.com/epoberezkin/ajv). \nHere is example how to implement uuid validation for a url parameter. First lets create the Ajv schema object:\n```typescript\n    // schemas.ts        \n    export const byUUID = {\n      $id: '/byUUID',\n      properties: {\n        uuid: {\n          $ref: '/UUID'\n        }\n      },\n      required: [\n        'uuid'\n      ]\n    }\n```   \nNext in app.ts we import all the defined schemas, in this case just `byUUID` and we load them to the Ajv validator at service startup:\n```typescript\n    import * as schemas from './schemas'\n    \n    // load all schemas\n    export const registerSchemas = async () => {\n      support.schema.addSchemasRecursive(schemas)\n    }\n    \n    ...\n    await registerSchemas()\n    await finalize(app)\n    ...\n````\nAfter that, on the router any route can validate uuid values that are on `req.body`, `req.query` or `req.param`. Here is route that expects uuid as url param:\n```typescript\n    import { router, Router, support } from 'micro-kit-atlas'\n    \n    const uuidSchemaConfig: Router.RequestValidation = {\n      validator: support.schema.validator, // Pass the Ajv validator\n      params: '/byUUID' // The $id of the schema\n    }\n    \n    export function init () {\n      router.exposed.GET('status/:uuid', 1, async (req: Router.Request) => {\n        return {id: req.params.uuid}\n      }, uuidSchemaConfig)\n    }\n    \n    export default {\n      init\n    }\n```\nCalling the route with invalid uuid will return error:\n    \n    http://localhost:8080/v1/check_status/get_uuid/123\n    {\"fields\":{\"missing\":[],\"uuid\":\"should match format \\\"uuid\\\"\"},\"error_id\":\"1adf7eae-c488-47b3-8c91-fb5942c60444\"}\n\nTo run the example:\n\n    cd examples\n    npm install\n    npm run support:schema\n    open http://localhost:8080/v1/check_status/get_uuid/with_bad_uuid\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client \nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n \n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html). \n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@8.1.6-alpha-1","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-ey3c3NGdEl5RRp1iwonftsawRaiea71eeGw4eZbPoeaJOh++magWgRpGpbz5rlDKfabuYcq/DKogn3a1zS4+Yg==","shasum":"bb5cf65adacbb51239342dcec5643d2a0b223f04","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.1.6-alpha-1.tgz","fileCount":60,"unpackedSize":148654,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeQtLmCRA9TVsSAnZWagAAGl4P/j1deDFMxZht/06yzM3B\nwXPo3GLGBb4jS3CD5BIuwkDJmMgCJWicNPbobn4zqm3WY4Hvrrikl1zarjFI\nieHFCOrszCVIWta9In/i95MiqbPaQbVlhy27h406h6uHlER0uuhTCMVXa0KZ\nEJ0jfstjRHzLomi1ZQhGWSt/SWI5yRI8g2FVSb3N7JugrVFN4C8wxbdiSrEF\nwAFImztoUaVUSiNLCyqT0JDEzq8InhnmsaI4hXxwTmck8H1mT1wEAPbjqrxo\nbSQ1LIVrMGBj8Zw1nE+iVvOAbiFs0Jt0jTR+tybPHus0pZN4YVfWXsPUuwYJ\n0wME5jn/nqGF3jt4pJM8JOIidTEkmM9XuXprTnvJOgghzsOIPjOzZbBw+rqE\nuGpoTTLDHibflcNK6R+OcCcVl0QMKESVDkhMS0E711MbQf6CrRporE7yQg9n\nJkDbUmv5hkmResF4neVFnORe1v0ox5SGz4UN6Oth9pLYZCkTuDQAc5GK8vl5\nTQZvC6HM+FoNgzXMoUL+rTCOjGUW+Mq5vzHMBfZ6l9gpWVr8kHXhU9VTKF5W\nTunkFzclz4tpacx2ZzGqnlhZt8SQBDqCFxe8MfOvpGB77f0WECpxQ+k6QgCy\ni4lRydzLBCyFPyd0NoMIl4TiEsQigZdtoSDifn4SBP8E+ZvZh2a43m/K1csC\nXE+j\r\n=ajou\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIA+6tk1wMDoz0zEO1tA5LY2Wra1wrMF40FMNFMgKWZmxAiA+/pH6GP6eHhPViLAOXxtPrBclOFvnURwRjDRr7d94ug=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.1.6-alpha-1_1581437669798_0.4072054339123232"},"_hasShrinkwrap":false},"9.6.7":{"name":"micro-kit-atlas","version":"9.6.7","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"8dfef0fd1e06b15d1a02edba1f322280f9384598","_id":"micro-kit-atlas@9.6.7","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-9w8uZDThv2IxvRRf3pzLXS+3tscKcbRk86WtRWMArmMHCQgoMm5qrzI+8kcseT7hIz8HreA3FY2IoDj0C5eeKw==","shasum":"5fcd6763b30f3c066168db95005bccb1c33f5973","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.7.tgz","fileCount":120,"unpackedSize":345881,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeU7+jCRA9TVsSAnZWagAAp0UQAIUwWdx0iio4wR4Xnhhv\nRB9ht7RWDYg7mxB0WK99WMXGZ5NoWkmuMURNtaTEBtwdqAzXEgjEb9xBbj7v\n621w8WsDRoXm/3DtE9SzWSU68cDUT2ani6tSgtGeI3j5ucBtV4r1ACseOaWF\nW3GPR0PKL9mByl8fpJzgn/U6jHYvk4xNqZklWwCeg11H7MMFwhnDqD1FFDEW\nIOx1QVfrlnlP8PZvtkL3/GO2hisVQuJbt2m3N3DWlnJLJyMbsbCa1uXsMc+o\ncr4UTqP01x+fvh9coVl/YNGnK02051TxFW1ukdH1nd0+PyxXSokCKbP1L/vj\nDA4qZR0/gHxnuoIdQxTA/Ckgmi4yuWAv6F7TPcGqry9j8BXQLpiLvckTl1nv\n78ldTGjzTinNd+szay6VCaIFvMOnC1iw3zuftIatkaS90IKauSdLyx+JfyTt\nDFPVP8uKn19OL3eB6i8Ehirl4SHF/m1Q9fVhHTbLByItgNuk5XCuLN7c7ac1\nPrjgts4OoVC0Rbs6eBjObawwCUnIsztYjZ2haE5eBxXshMeipTU3MpKfG0oh\nI7lQO+EpF7auwsH5K1X8PWxxsYgAoiMD+7MN1QMKeB4H89Ce+uvLSJhmV+dK\nPk0dEEOP4Bqhfy5r3F3DPf99BEgZiu6wNXGQfjPt9aKriyeGAS/SBdCavRnU\nWfsh\r\n=BHHM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB1ssAmJFz4giwwrLhLcaBo6E/42v3jVHKBeNnAus/zrAiAuUcG//vfg3hDZDN3u55BHdbyRSZ2BDLR1opzSPv+BNw=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.7_1582546850617_0.3589637826106764"},"_hasShrinkwrap":false},"8.1.6-alpha-2":{"name":"micro-kit-atlas","version":"8.1.6-alpha-2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.17.1","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"~3.1.1","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"fdbc92883bd94e552432a22da792c99be18b6d3b","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    \n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n    \n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initService()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n    \n#### TODO? \nDescribe init(options) and finalize(app)?\n    \n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Support.\n  - Ajv validation (only for HTTP request parameters).\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n    \nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `host`\n_string_ _optional_\n\n**To be removed.**\n\n#### `serviceName`\n _string_ _optional_\n \n **To be removed.**\n\n#### `service_root_uri`\n_string_ _optional_\n\nThe URI segment that identifies the service, after the versioning and before route part.\n\n`/v1/service_root_uri/route`\n\nIf this parameter is not provided the routes will have empty segment.\n\n`/v1//route`\n\n#### `namespace`\n_string_ _optional_\n\n **To be removed.**\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted. \n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n    \nRouting\n------\nFor apps using Atlas, routing must be initialized between the `atlas.init(options)` and `atlas.finalize(app)`\n \n#### Basic use\nroutes.ts\n```typescript\n    import { router, Router } from 'micro-kit-atlas'\n    \n    export function init () {\n      router.exposed.GET('status', 1, async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n```\napp.ts\n```typescript    \n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    import * as routes from './routes'\n    \n    const options: Lib.Config = {\n      name: 'check_status',\n      service_root_uri: 'check_status',\n    }\n    \n    export async function initApp (): Promise<any> {\n      try {\n        const app = await init(options)\n        routes.init()\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initApp()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n    \nTo see the example in browser open `http://localhost:8080/v1/check_status/status`\n\n\nThe Router in Atlas has three interfaces, _ExposedRouter_, _ProtectedRouter_ and _InternalRouter_, available as `exposed`, `tokenProtected`, and `internal`. Both of them have the same static properties but with different signatures, the exposed router requires a version input while the internal defaults the version to `/internal/`. \n\n#### Exposed\n\n    static GET(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The express `request` is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\n#### Protected\n\n    static GET(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The ProtectedRequest (express `request`, extended with `req.tokenData`) is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\nProtected routes have a middleware check that the request has hit the API with req.tokenData attached. \nThe tokenData must contain the fields `globalid`, `uuid`, `client_id`, `scopes` and `grant_type` to make it past the middleware. A request without tokenData or without these fields will be met with a 401 Unauthorised response.\nAs a result, the controller gets a ProtectedRequest instead of a Request, so you can work with req.tokenData without worry.\n\nExample controller\n```typescript\nrouter.tokenProtected.GET('identities/me/is-dave', 1, exampleProtectedRequest, { schemaConfig: { params: '/IdentityUpdateGetParameters', validator: support.schema.validator }, })\n```\n```typescript\n\nexport async function exampleProtectedRequest (req: Router.ProtectedRequest, res: Router.ResponseHandler): Promise<boolean> {\n  const daves_uuid = '86d7e731-da23-4e2f-951e-81a04665f002'\n  const gid_uuid_in_token = req.tokenData.uuid // Router.ProtectedRequest says req has tokenData and tokenData is of type TokenData\n  return gid_uuid_in_token === daves_uuid\n}\n```\n\n#### Internal\n\n    static GET(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n\nExample:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\nExample with redirect response:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request, h: Router.ResponseHandler): Promise<Router.CustomResponse> => {\n        return h.redirect('https://globalid.net');\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\n\nSupport\n------\n#### Schema Validator for Routing\n\nAtlas offers json schema validation on the router with [Ajv](https://github.com/epoberezkin/ajv). \nHere is example how to implement uuid validation for a url parameter. First lets create the Ajv schema object:\n```typescript\n    // schemas.ts        \n    export const byUUID = {\n      $id: '/byUUID',\n      properties: {\n        uuid: {\n          $ref: '/UUID'\n        }\n      },\n      required: [\n        'uuid'\n      ]\n    }\n```   \nNext in app.ts we import all the defined schemas, in this case just `byUUID` and we load them to the Ajv validator at service startup:\n```typescript\n    import * as schemas from './schemas'\n    \n    // load all schemas\n    export const registerSchemas = async () => {\n      support.schema.addSchemasRecursive(schemas)\n    }\n    \n    ...\n    await registerSchemas()\n    await finalize(app)\n    ...\n````\nAfter that, on the router any route can validate uuid values that are on `req.body`, `req.query` or `req.param`. Here is route that expects uuid as url param:\n```typescript\n    import { router, Router, support } from 'micro-kit-atlas'\n    \n    const uuidSchemaConfig: Router.RequestValidation = {\n      validator: support.schema.validator, // Pass the Ajv validator\n      params: '/byUUID' // The $id of the schema\n    }\n    \n    export function init () {\n      router.exposed.GET('status/:uuid', 1, async (req: Router.Request) => {\n        return {id: req.params.uuid}\n      }, uuidSchemaConfig)\n    }\n    \n    export default {\n      init\n    }\n```\nCalling the route with invalid uuid will return error:\n    \n    http://localhost:8080/v1/check_status/get_uuid/123\n    {\"fields\":{\"missing\":[],\"uuid\":\"should match format \\\"uuid\\\"\"},\"error_id\":\"1adf7eae-c488-47b3-8c91-fb5942c60444\"}\n\nTo run the example:\n\n    cd examples\n    npm install\n    npm run support:schema\n    open http://localhost:8080/v1/check_status/get_uuid/with_bad_uuid\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client \nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n \n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html). \n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@8.1.6-alpha-2","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-eIoVmXnXob7hxxHay7YBvFPM93s6v0ueC8DGvYhFYWM8zfym4AtIUpx33saYut3GAHv+ZTutKW0KR7RqBInoVQ==","shasum":"1a9046b71e6a869bf74cae2aec68b042258b24ae","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.1.6-alpha-2.tgz","fileCount":60,"unpackedSize":148881,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeVRr4CRA9TVsSAnZWagAA7d4QAISsJk6EULkgNByufxFk\nS6k0TsGPgCUoZRrscNBT+GwyDVhQcSqpcXGdWOQtkMDLiuF2zmqvCqz0+yvD\nV4mu6GYNKYUtiahtVGV99xb3xjQAcMK9WQ0k8BRm3MXS7sw5VKsKzxtLpIa8\n1LTuROePn751pF/Zd4mQldGsfkqeT0QirSGpv52voOlyhkd8/kBkBS9cQsxs\n72bACKJJWpsxVPuBGbjI8vtqSPZZLvzFZCu0nhxTP54H5Dw+dXV+7wHBKB8H\n3BKDKe8Wt3c/QRI1RuH+WTrbc/V4iI9r3Ppa3LI8EQqD06B5pNJOT3hVcpMA\nwzRlcq7FF3/O4GtKRdhnntq7+R96GaST0HL9iM+KCGKluwy9t0IJqChfCIqc\nlUyGJpcnVGOl+ouwCCEICrE8n410pK22MDe8HHPx65n0MEmi86wpef5OnbCs\nX+t3sVW0eYtvfn7IDAtQ2UcRxpNKVdH0Yjp15oo9xMV4BPOqDSGNuo71kze9\nxVfJ219jgBok1ZSMXr4Gx+evZ04tRCMUdU/0c8sN01g+PVgsq7XzRFEhpdjA\n/+MEJPSU3I/WjbQ42aG7OGUinyEUQa/tB2ZNNTs14K9rI69mv2vMU5tf8nIc\nWJG76wlArfkStLWY+sdTDOGmkuc+qtH8OUrHhxj5x4sC1+AI48/sRFGL8OtL\niWUA\r\n=vVVv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCJurTBer/5DsLyVs9SeQp8tC+S348ZTrGDn6EmO1VIqQIhAMTaU4akqrtTvgSeSfZCsn/alAMod6lsbAHnB8qCwnAG"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.1.6-alpha-2_1582635768453_0.6770661028033464"},"_hasShrinkwrap":false},"8.1.6":{"name":"micro-kit-atlas","version":"8.1.6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.17.1","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"~3.1.1","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"fdbc92883bd94e552432a22da792c99be18b6d3b","_id":"micro-kit-atlas@8.1.6","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-kO4Illzcshn34XlWVayxUIAbC3vpuyMR/Njh0P79vWxNzPSi+s1EF2G+8BFE/GkdOWXS+rkdV415bGfpdpRO2A==","shasum":"7c060925477ebc6e5b1753a3175659d599ab287f","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.1.6.tgz","fileCount":60,"unpackedSize":148873,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeVSrbCRA9TVsSAnZWagAAoNgP/1Wd2oWPiaZfPXP57WCA\nfWqN97NFGqh6l7yyoiHIwHDFXb5epYJFxuJwwJg0f9Lmi9x0/SjZK+BRmJo8\nrcNk7X6L/qUNyZ4rwtymgGyq0wTui0RwvwQgaSAzArUSduAAR2SpfYViaXhH\nwzd+A1BSdbEfI1PyiH7aBh5oYzaPbm1k9cs+u66bUoUHFt1hfY+FiDnvTGII\nAfEYAwalkTdPR8wYKZ64m4UR9M3N60l7sRe9WMRcj9nv0V1t3s2yKh0TdC//\nlwgYr/df7l85Zszc/OkML5FS7ta+hM2CphIVHVczw19GG/xV2/+un/reEK3T\nnKn3tQCyfw5CBi+t76UR/Qww4eNl5o9Fwgx6OvHTrQ1DyLuKYOpi+EsQgepl\n1e8Lc0USs6d7pkzgzPrQIdXvAfJoEOXrERMu9ccr3+SAftqUyDmO8LWb6jwh\nxpGzABIwDAKuGaKDUMjJ8Qk+nn8Q11yVd1r3EemF7f5zhaKvTL85ChBOSTPM\nqTRKkm+3lX9cUSqkz1QCsRVXeA2f3T4Jx9acXpI8pr71NifscPh5iZ+tFfPw\ncGAUMobxx/yGl0w0pUR42Kq0utAVspnaKXgh4w1S9kui9ogbsws2jCcKA3bc\nSm+HKXTynpHmyJ3Rfw1d/qKjipeJ4htgR9oNOVJGyH9ghTEfHIiEfZGMblN+\n3bRD\r\n=HyxW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDSy8uc4HOK9qqg2qxo8DnHPV3octg1qrpnJTyb/Zu2kAIhAKQtIL7EhI5kOK56ACotmfBDPJ4XD1rHW+C+W3YxCPUL"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.1.6_1582639834263_0.9172631685375816"},"_hasShrinkwrap":false},"9.6.8-alpha-1":{"name":"micro-kit-atlas","version":"9.6.8-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"7fb74707a59225208d9dbe4c1079ebd1d94ceece","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the null value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.6.8-alpha-1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-upih9QYF8Rpx8BNqpHXhnccPJRGG/07MExEpoOQp/u3KcRjdREiq/BqPHoqa7gBhYIZLqjlVmQL++mZODNaIhA==","shasum":"9ef286200e3dc46e928311779477843c983f4dcd","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.8-alpha-1.tgz","fileCount":120,"unpackedSize":346077,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeVkNTCRA9TVsSAnZWagAAF9sP/00Zqhm4uEMUno1FpCwS\nB08GaLjkVKEscT8JFGx0abwJdHarraqsYraLBkIUP6AyONqstJZR2Ygnc9NB\noV+rmTqDdRPTWZ/dUTReki1ipDGA+AIDrnzhUGg8nesBerzr89W+2CzLw5kP\n/6H9sElIN2VbpKs2ub5q3j4ijn/nElj2APxU/1ZdLDBIdTb8y0F9/jqGCljF\nlwXKdjiWKI5QCJtPrTazNJYDWbNu7zRTIImXQb1IubVDT+GBd2OpeHwX+GuJ\nzmJlaW7plvzJnv6M3p48CsNWKQwN0uvh5cGomvfMpY/GHH0Cm4kAFQJi3Zbf\nJeuw+G0n1btU6QY7YwsGgRtais8Qe1Jo0k8EydexgSibMpAOJJkoU5Q3SVPr\nLw7+WmBEnbwSxpuedh1BkU1ygUhjNVp5J3HUqQZYkjqm2I/u5xzzdt0ouT6R\nQyk2cJbeDipvOVT+l980RlKLYEzRvz9AIAlqWInoPVOVRcQYxIpfvT+SbbIO\nnSJ6nNavtcuofaa1CT0glpZS2va9M9ZXQDhNOtCZ+REJMRvK14KV2XiE7QRs\nN4skP69bFmhjNLUoLdAVUp+MDeEV5V69Xwml17RvAfcc6EgNixXmKw2GD74K\nNGEYEItJCrSvZFTTIkRdZHlRIpiT6wpYh0CaiHkBBvhOXK4O87ncI4lswcQn\nGgJ6\r\n=FvbZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDqM/DZgnlyNVknke07ELPmOnPlnTyIAMeOMlbDUHDmhQIhAMx+o3+e7zpCJICjK32LMyvvzazOUMCLAuICOW9PltZP"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.8-alpha-1_1582711634529_0.8080750456500736"},"_hasShrinkwrap":false},"8.1.7":{"name":"micro-kit-atlas","version":"8.1.7","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.17.1","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"~3.1.1","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"1a7db4d1fc5cf41b03106dec70b9fa45affd80a0","_id":"micro-kit-atlas@8.1.7","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-MTJ8+uC6mkTS8wBOZKiA+twhZ6D6ndFz3hSlX3rCBnl8X3hMSI6Rlv/WMOne8ruIks0Nw17Q1Z5Do81S3GWhLQ==","shasum":"a1bd0a32ceb7e568af4e40802d51d86f39177e15","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.1.7.tgz","fileCount":60,"unpackedSize":148954,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeV35aCRA9TVsSAnZWagAABIwP/0KJt89on91cHSUiZBW/\nRgdrbNn0ktMBaf3KKfW3SO4i+sSGCPsVyf++LxGfO22CSxzYsDfvt40T1G3H\nF/QZurSliqwEIrqzt4J/02yvCTwTKibByVqECA10vupqc58a1ZE4LO7xw2tg\nHH4Z9QPP6xyWti7s+FBMAQN9sPHnMfb96iTPfD8hNs7l1JWoSYuLHe+A9jxF\n9TKQAcWf3U+dsYyidg8obxRfvrM7kzxlMhNFQoJT4TfoYIAj9lq8Kib0B3N3\nAnIsqBwCux3ZzG+l7+am7fAEwBLQmuw0I3Dbs63dIuvZkoJhot7LdsFbTTLx\ni7OUJKE4WoDOdsgUUAjS0UgmrUyzXJfpx1Rzg/kxn+HVneMKng4m/vo4IGBG\nbrq0EonE7qRMB7sAH5KQgm11aSOwQ8ra2t9LXvJbQy3Od5tu3zTNJXPKr6is\n1FW8bAlZlHje77E97PvWrZMzKA1EZpmU/uRATfJOrwvv5wfvWQpOKyPKWTfP\nVFRkW7kbhzdFQ2t4HuZ5MOaF77F2SLf4e5A9xDHXksAdDwTJ2xu0vZ0ZxfMO\nM9V06xGXAzDxCilLA87dX6KKiS1eOG4yduIAaxVgZO007kGYr7TdjZSKaXJO\nLH1e5/i7h0dX8zWblRchlYe97apkPXdvu/+1nQGJdYZtpmmHb2sm0hIxAdmM\njhIy\r\n=QT+3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDhsF+NMAdI3uiwJwnLmQyLKdKCESuy1w5SfWh724s+DQIgGg2KSdcypCzorwFFo1aJKd/3i7s79owkx2lyjZ0r/uw="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.1.7_1582792282479_0.6789950611026647"},"_hasShrinkwrap":false},"8.1.8":{"name":"micro-kit-atlas","version":"8.1.8","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.17.1","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"~3.1.1","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"4c40c2a9a130b82f6c7e5ac7bd8bab698c250b82","_id":"micro-kit-atlas@8.1.8","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-F9NndPk3tld2etZJ1W3cmTiCHhH2syZIOLmKPoeQuiW4nx1fkDPzODICdsEp8b/VGvRVwnwOtR0GPk9dlUIj4A==","shasum":"2b692a53528291f76a600505fa2a8456b112c2cd","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.1.8.tgz","fileCount":60,"unpackedSize":148954,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeV4S0CRA9TVsSAnZWagAAYzkP/12Mk49mzdIw+JUI7dSv\negzaxGId52deOFnFgslOH4Qbzo8ACUid2qtYacQJKoQ9w4iptY+NICWzFDHJ\n4+/beXamAZvX2cDw82g0/b1uYLFB6RZqXci3CCagZEjTz3z+EqYqDpK9J7AR\nIfvGGuN6J4O2sE87VpbX2JHRIK1RGDuIgtPUAhHueJaeFsuvhuY0CDk+0Aay\nSNY92A7hlyjqoM56dTS+sGr6oeT8wGI2j/ssAGXi+7lRH9rMZKRpW1kIMzCH\n+Cu2TiUCxZntTpszNHC5XFZk5g9ZGfVxq44GiTCA1S4JgBtEtkizoVknWbmC\n85ND6xtiGqVK6z0v4H12VRN2x6AIZ1IECj3tDZACh4NqyDNxsDKjEtt20c6B\nukLbw7CQYrUMdcYGQ4Upc3tIvAu+ugGiDODJaPw4kQH103D1v/+qWhtWcy6o\nn5vnaxmXEkCci5Dusr6d8MOuj3qmFmKeZG2qKQoKM0jdSRn5xwfTorDC89Ok\nF3Mntf9BV6R0ndnK60cxMQ9IQ0MohGO2kbudh7EdvNaZ1wsqFKdqrRzyO8DD\nPN7CDXqipDZAzaYszVVHv4xcgSAlGvqWAXwgt5YhV45mBo9kLnJz+5/HTAuL\nIH1vNLusc1TGtxiHde/JtAGqxZCeY9HHaMQdzMYUC58yJfjseXMDqUhmPhya\nmR1G\r\n=8dDp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCsgVOkcoQjs6Q+jgQNvUXJYYAeh+AVVlVslzOwivI7YAIhAOFCC2fOMQYW98O3w1WGdOaYjGtKckjGHePue6mqRlPD"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.1.8_1582793907821_0.1255932464874614"},"_hasShrinkwrap":false},"9.6.8":{"name":"micro-kit-atlas","version":"9.6.8","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"a77476a77003c091ae160eb83bb78421bfadfd6c","_id":"micro-kit-atlas@9.6.8","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-Pt4R2hew6cfccTLfc3B85tXJj7airS4RVkIL7573nyy9bWT5IKHnRKSpTxXxwP7/gFHl97QLFf+R+GlSQW5Elg==","shasum":"4b301d2e86fdcf1e3e702c889f3e31e586ea84e9","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.8.tgz","fileCount":120,"unpackedSize":346150,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeV4VPCRA9TVsSAnZWagAA2oEP/1KMPB1HU9bDWQUYotsJ\nr+tyhSeuJKIwjoODEoreAGZxILqITpTZvOG/lNF/RzQfc8wqpHwW+MfYiiwc\nIiwxPeolzcCZORTR05S/jvdtV0ocDGxVhR7qsytdTGzJkUPwnxhQKYJZ6oN5\nfns7hJVJWTuqlAHp244m2vqG0vdKfHTEfPnPVMBWat3r/kLV709BVygNzX/T\nxGrIj33LIsayx5mppbWFkwZmViW3OqlXStzr7P+Kps8MAvCT8oOxkg0AjFqs\n6sVyjp0+lPLFYNHoo56q1GI7v0PTEBxc+S1TwlLkJffIsnDDvqQXtkuhQDLk\nbusBX7Srt61oeZv1WVO+ROlmKj05AEYpBKqKsgH4hJadp7TQb9zR11nuSisK\ndWymqdfCuwXT2hFYkvUg4B9IJgK4xqOhkvShUoFWf3964SeDak0SfLwjivL0\nrPAJudKtMqV3ZqOUI+DUOnPhGq9tIuAYzkGbau5IlCqjzCdUY+6Q0Qa8E/aP\nne2UbB0bJ735rJ0GQkRAeah3qV70c5mHkiG4a5eYEPHKDjthrVSd39OWK9BX\nhjCeVm6aPSo7K9hAjDMnKXvvcDhwY1vbrCylLhamha9W8+Gv8WUofOYVoo1l\nCiSdBck0IB9i7e/KjEenQJ2pgrCB5/k5r0mq9kyHNY26ek/Y0J/dHeJBFqUa\nJscJ\r\n=dNQO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHq17qhhx9PvXExBRWH/kzqFjIiRlU7t/SR9HjADjHvtAiAYABY5fvVxbblKUwjHaAJEcUkD4MYAN+tRe0NYWhsiSg=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.8_1582794062602_0.8930466288169538"},"_hasShrinkwrap":false},"9.6.9":{"name":"micro-kit-atlas","version":"9.6.9","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"6d04be520cf7c947a5103b59c250878a7906ec3a","_id":"micro-kit-atlas@9.6.9","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-JlEGRihj7n4vPPU03KIR/sRcoy4IVzwP6dbLQsWaKbP5b/FOHMj4f0IHOsaqjXDFr+ydzVpj7QNZz6R8xVtP3w==","shasum":"185783ab9d6c981534277c2b6b7bb6193a4215d1","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.9.tgz","fileCount":120,"unpackedSize":346805,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeWO+MCRA9TVsSAnZWagAAaogP/1Ptn2xucji7XambmKc0\nxcGuIKfOjMCyoduxqLY119jr8nsRB83YSexigtqsBIYHyr8qTOrZ7thFqPpH\n11E36/uqd9eu2gxIoSgAIoRpZFK24z+VJJ5ByXUlBLJg8u6h/zHUuwObcybI\nutKxhyaOcvxkGqeZeybRfC193uEJV3CgyA938Y1FczKyT/ZWRUeOn/12xRyB\n5XtHGUhadLYwym/NFg04juHLg9t+ogNSdX99M7r/6Y6yQA7DkhR7DVrXhH/Y\nvZBeUM435K4+NCr/QRmqjbc6ICn0nWtIHcFrIqtXUMYbRON+tY4abh926Vnq\nAbqM1pT/mHHIZNdNJmMlYcp8W1bHDIO3Xr2G8z6vh2bj+XO2S+dQQQkavEZO\nrxsfduPXeN5Np66RMUIG5Ono9nGIRu0aF2tguYcHKZqB2Bk6cF8IxY3Ff5/R\nozO8lHevW6oyoDU48HANmezyF6xX3ELphh2RzX4H7/qCd8WwHdmac+uV0/2U\nQG87LPE9X/QvMWicGum9iyrgjpjxggIUSGPCiHoCQdA/RJIiSX+6IWz8AYgF\neZeP6+Xw5o7McZYsc4q6lS++bvL8wzLjJ/j7p9aryg/4zvnoIVOH8+HGtPOL\nyXaozBo/YPQO47hdrGxfVRkd7DtQX6M7d7yY19gdO2oi6n5B7JSHy6zYTQTf\nQyGU\r\n=VtVw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAinPhzGirnv55CRnDOqMrSadT7BOmRfXALOVsKX0/gzAiEArx9cb0RsbVYJspMCT6XPwylWjVhhimpyoF2wkZFEnK0="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.9_1582886796214_0.651607325562575"},"_hasShrinkwrap":false},"9.6.10":{"name":"micro-kit-atlas","version":"9.6.10","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"cd1bfab9a1281b8f236cecee72c46a4c3884cb59","_id":"micro-kit-atlas@9.6.10","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-X2n+VbLjYdKn++9VPqi2GaWmItDc+L8Y+Bmv/U28fg40tncm3N6ZmPvQ7TQnAIxwzNuIzH4QmKYzzU62iv1G9A==","shasum":"2eb75decc257b706820bc6ff37b240e497c81f65","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.6.10.tgz","fileCount":120,"unpackedSize":346725,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeXhl+CRA9TVsSAnZWagAARrgP/1EdAWlLB5xynz40x0NO\nGJUK2ixT5+yxLhe6G1Gg+hN0k2QlvfsmeWjfIaWwUWmSUcdB25J53GTMJw8g\nzZEYm8eZEraXd1iU3k3C1SbSznoLfqGFp/rKLIVmIlQo3t8lOzSCQGlmqw/W\nUxoz0jr/foIVhWSh6RqPoG4zd8ICzJI0FaMTfWmSb/nFGDw1xQSD26ALUeM4\nF8RPAVmD3bXjNBaQs6XuA8MEAZzrg06qWL2SAI/omLunP6/CWxDrbSTvAn9x\n8/h00IBMji123fa6Z0fPZWW0cYIbQUG2MzSAw+sszTQfHuYJ2xEsKDJDKrru\no28DKLkVjow8iGVy3oHvPtyi8mQCvoyRAgxaLW00nsY8O+BGa7/gtufhcTSX\ncwM+35557ZKTS4/0yIzfjLbcHDlF8jxF+axuCOFjgMJRJn8Uh5KyTrMJYSDr\n65R37nUym2JlRSXZvyawfxaI9emOpAhl+9KRVmW3rNAl7RrWJPcFddQiarS6\nCE5sioQFvtg6N7ssJxI0A0uR3vPHGnZAoqqKoBuUZjFdKV5krVNpmEyDkRlz\nnbxT8llZtt0KfWNDB+WqFNpkVUq66PhzqcX2CJRe9Ao272sriY6DO0xumN8F\nbvY1lko7IfxVXiWoQwW9Qd/JxJvIOgx6iPgK5Vb93KaKKEdSOVK8YA9KyOfG\nWVWT\r\n=eOGH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC6qMl3KgO6h1mu9XGvYhBgEnpoErKeWtKbRBGw6cn6MgIhAK4Dg/1gcvMZMsenCYU7/aEoWTzLtsg62IJnDyyOkI+V"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.6.10_1583225213237_0.07284520349349699"},"_hasShrinkwrap":false},"8.1.9":{"name":"micro-kit-atlas","version":"8.1.9","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"^4.0.10","@types/mocha":"^2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/supertest":"^2.0.7","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"^0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"^2.9.2","typescript-eslint-parser":"^11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"@types/ajv":"^1.0.0","@types/body-parser":"^1.16.8","@types/elasticsearch":"5.0.29","@types/express":"^4.0.36","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^8.0.17","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","ajv":"^5.2.4","aws-sdk":"^2.94.0","bluebird":"^3.5.0","body-parser":"^1.18.2","cls-hooked":"^4.2.2","dd-trace":"^0.17.1","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.15.3","hot-shots":"^5.9.2","http-aws-es":"1.1.3","ioredis":"^3.1.1","jaeger-client":"^3.11.0","lodash":"^4.17.4","micro-kit-aws-queue":"~3.1.1","mysql":"^2.13.0","mysql2":"^1.4.2","opentracing-javascript":"^0.1.0","sequelize":"^4.15.0","serialize-error":"^2.1.0","umzug":"^2.0.1","uuid":"^3.1.0"},"gitHead":"63942e2791d4d73859343e72d3c00dc5bad3b660","_id":"micro-kit-atlas@8.1.9","_npmVersion":"5.6.0","_nodeVersion":"8.9.4","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-EU0g4RP8BAY2r7XVazD/0YrHFTMw0OSGcX+cKcdSfDIch2Z31p3R8kmiLrDmvErlsajEQJvTppsrPKbzWQsPEQ==","shasum":"86601581750b1b666b210a1d94457a3870d5e07d","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.1.9.tgz","fileCount":60,"unpackedSize":148873,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeXjTrCRA9TVsSAnZWagAAcGIQAKP4sF0uDPRhEAwDEbpH\nYAZFzA1MzKtocMDpUXQXHVEH4vUGeMkyirIyLFeQH/qW+p+DR9C47Pzf1cBV\nTsCDhuaPYA9Wngo2vcvyv159UnGQWN9DIl7+kgDOPFGYyLbPADXYAo3UuCkx\nnNWOuPa5JFoDjHHJUh/I2toHpFBgCr56ogQtKzuIUV2rZAs2K+URlcksZuWU\nYJGt0ayPFMWHNtJZbeVYRQecNd4Y+b3aZtLm/J8+K8r0vDYR05bWLnSwxvrb\nuPLEATNCFeJhn8Rer4LfRYzqJkfqWA2QuqpdByN5ELvHvEVYUdxQUinvWTuP\n4XR6nVKcCJdtQ8PT2XrPWf5tkVI5OtUkx7c4FDHtylHteWyZgdflloJKNzod\nXv8+qbS3Du1yYStlfXTZBO9R+CowIlNGzs8Sn/w1tKQ275hqxsVSJdkKfagh\n8z3UJEA7ziGHR+K+PbY2a1ItqmsxcnVrOa1yATYjYKR/0LjTsw/K1SvUcuOE\nP9U0jQu/trr1h2pLPuv9kxn6faRFbxEzL/ToFHXJQQl9xiRAFk6DctAitCyt\nDcTEe49UVa+33Rz49t89eKjUyYIAodC5jg6uggHvK3vVAiD9FtW+zHqhDZBN\nIjUTdEW1YtOm2udsWznnnZ9W65+NV4hVGEQktwXlH942hRp/NyUyLCvEZeG3\nOJSi\r\n=kui5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGOTxrOcLmBRRHgcIPPDFPL0tYhwpPgXHNi86SuMA7tLAiB2GKcJcmjw1Qfsx2IZxv1ktJxhC217/gk4twhqotBSXQ=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.1.9_1583232234651_0.501705585286188"},"_hasShrinkwrap":false},"9.7.1-alpha-2":{"name":"micro-kit-atlas","version":"9.7.1-alpha-2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"9015acf13a4c7c85af3bcc6731480ce92196e209","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the null value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.7.1-alpha-2","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-7p3BnpXQxBI2IPTZbrvbxhv1SAl+g4ZkWfPcLyDa0xCTDIK/0Alww7EbgQLY1vv5xblX7mFOSkFj2ZuKei1Kog==","shasum":"aa492c473445fdc11688bb4def33f669f6812a83","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.1-alpha-2.tgz","fileCount":120,"unpackedSize":347305,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeXjzBCRA9TVsSAnZWagAAOE8P/R9beBOON1ej5Y/jH95T\nF1NCWne6agybfLXAj6Y61wWt/TxLnjv7qbwx3DwVQ3wvFOObD705DhAkUIiC\nLGoONZkDZQj4zu5cHR3SHXz+Z7YZSCGro2/cLWkkgX85IkzRWj/xSJXJ9uyc\nf1xvyEeiiKHiSbTSu0AmGuLw+AYOqqB5WpOIcoB/J9eI+7Sn//3D1irDqRZA\neVxNdNzVEJxkzUjYQl7PwWAqdFo9fp4panXokT5fZ+Ymh7Q31oHzYK2PE0Ch\nlqtfLsaGLrxTZyY+Zzoa7k6NSjW3rq8I2+Y39i/pyVsh7hqphPTE9A+114+S\nRVBzFQC3Ma1bNu/aG6RFSH1kbQZZ2s6xeVNafSWVFfeOAEw7WylLKz5h+BYX\ntF6dExvJPBRlsNnAFqV2i7lHDU5fJtscf1C9lf0YkQo8/rIevKygAroRHB/d\nHvO2Sbsdf1dn/isSc2bfgwmkGMset1pbUV+3DfbXyojKtZDyuW5eMxhsKMBI\nGhiE48D3qR+WTd0fMZdDFpGKAcUfiA86OnuX0+NCI6tdhE7qFN56/IYL1/WN\nqBbSMVT54onwwHIDV0DB8Bm9AQ4fiBH7CHzG63SNn/Yw/AXtHZDeHDRHNFo7\nILzdohc/YPsW5Ha9EzNWVi8n62XCMtHCPIFLceZzwOztaVq+W7ygTs7LI4yA\nuvA7\r\n=+OfU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBuXLAvLApwHx6/8TQmECy65LWwdlCdj1pY+ygsSMjG3AiBqnd2paiLGVY9AdBkV1tQRW3w4WzE27O7BZIXsn5o75g=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.1-alpha-2_1583234241151_0.13708666137110503"},"_hasShrinkwrap":false},"9.7.1":{"name":"micro-kit-atlas","version":"9.7.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"35073067620a6ee32bbd58473ecaa62fe9a159db","_id":"micro-kit-atlas@9.7.1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-z8dno/NZGFm4kPzW19ZjpjJLn1Aqv1R9AjC8P9Lrk1vAeOJIN8avE9dUDTn70qhH/M2JiNCXL3bDBQaZAUKh0Q==","shasum":"0d09de08c602e02d25e7e6bbca7f7293a94e04e7","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.1.tgz","fileCount":120,"unpackedSize":347297,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeXmT1CRA9TVsSAnZWagAA6NEP/iZSD5XpFP6z/2BEibSk\nh1UMn9gQKn9+GdtP9n1q6gGe+bDoz5T4SiaPKu4uQ6NXI9o4Zt4/xUIbconp\nwOF5rTNgySFJY8Ix+QdIy0i5pA/Ev8LABrjQKiCu9qoRKG5wmFD4QWeS0Kj7\n0EBbh7WzN7A6p6s/7Wcj86zCXK3AwV5zoarJmECZxagmM8cOyJ2SVu0+u41Q\nnxjhYDICzXT/OcRn7brLhmY3vSAp24wSOQ51h5AW6UHcMYwXplyt2SovFMpR\nEP2p5JrDSnvSHDJRJt5fyJvF4cOmNfAhz1fgy5t6Gq7RqFW9E2DR/uk0GlpH\nhew3NIinAt7stW2Jui1pLsJpndTceSBf0Ou8YpxzOplQTakUy7gXBTT1T+kZ\nP867EGoXim+b5odhOQBGGCoBYe+yGlPVwhSwSTFczBPlBU/dsVm2HsKoplkW\nbfGSB2J1zW1KOFlipYk6eErzgFUUPY4WPp8E6u3917GE0hmzDXhetNnBDzI0\nEXjJFEpTVTmfysrpX8IMvwkIuOAZ3HrrP+ywoewPr526CpeEOcELkb7Yk0zy\nSZ/TROdCdKfLi10ry/KFWYJ8fcoKevzHXowK8I+TSW18Cl1yRpqoF6Yx4pkq\nevGaWY7HdP3HRi8X0CWO1ra3XM2euqQ+Lddll6ynS9Q4qUYF0bxLbz99wdzG\nUYTE\r\n=hpXJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD2OZzT0EXSDzqRjqKQhx5G7PN1IuXrKPh5lbJja0po+QIhAM6+5p8myRvK7dCHhrtaq5Pxd7NrSkieGHREz/54iWI6"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.1_1583244533081_0.3566810142168555"},"_hasShrinkwrap":false},"9.7.2":{"name":"micro-kit-atlas","version":"9.7.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"9e1fd1695d2477f9cab06bf40a78831db2bdccf6","_id":"micro-kit-atlas@9.7.2","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-PacUlntMHV/7cbtJeHPaFLwCc3niELdAoiVcAbQWNZIygzc4odDUo4/hYGgbJEkZxiqpAB3RD1yTBd6zghK6Jw==","shasum":"36094f19982c83ac5c5250fe3057fba762994497","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.2.tgz","fileCount":121,"unpackedSize":348564,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJebyydCRA9TVsSAnZWagAAdb8P/jzSsfNNvwNYebWteIhv\nt5NGVpWAi0h2I5DKHGuXspRkrNPUyi0zeziQOZR/dZhUTA/BEHd/hzNuqdZ5\np+y6oLXledQLou/J3d1QtODSY3FY4oV6XRgiJsHVdfNuQ0rXAbOp6To2ygZe\nxEDA/xty5Honwadq5D0gShKqwhtSFh8lpQsPowHjmg84JoxTT3+x00i7xkNQ\nzsBY0SObUVUFhX/Nlpg7vKEzA4NNNEDJZV+IWNVtT5eseUwNVDs14nnOomX1\naHCQMDjzxsp5lRU1a8UXLWiF9BxaKYsqdAnUKjH/RHtGly6/bgPJaLemSHkh\nJLMH7Dp0LOxeuVCBCs/WbBHrNEAkv2LJ5CfA1D0pRtNO9SM118lmQfZ/8s6p\nWB0zXUfcCfXA0Vnv8nJC84qqM+jEVWEDCn1yLtTNWGTAbuFB6oJDEYKQdzLx\nkrU6GhbPiw6mjs4362yROH8kbDfxNzz9aC7JX7HPTmegETTdlQ18wv+JVorW\nNHI6pJGKufYbpOf6PDGsHPCtEMhYE7pd3eCP5AQTr9ewTGHW5jxUHNT/AUbq\n7pU5rgyVtJiMDkL+V3j7Ncsw+tGZqCPUSzeamarnsVGv04+WTxOLaxqcw/9k\nxorbzVg/I07iH3CQRPU9ErbKGKphDchn79SJ/7gNdnEDUycVUGc5fRudxATR\n+UjL\r\n=4JHo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGD8SLYwU+TpREc2BW6voyMUhoy9LiCrDbnFlOz8qY4bAiA20Glro87uVKR9JHPagwMlG6RrtZ9SaGO6K9FritH+1g=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.2_1584344220942_0.08989240077217153"},"_hasShrinkwrap":false},"9.7.3-alpha-1":{"name":"micro-kit-atlas","version":"9.7.3-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"a4b248517138bea4fc1da0323870a7310446cdd6","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the null value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.7.3-alpha-1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-EO4D5OpvCkWY7PpvQH6qkXa4H1q3JhpSsAJB750fyVjc0OuCgLWnMcmVM0P6uoj4MVVIML/QEaVNhncW2YZRbQ==","shasum":"785f38792bdcae6c83e571d6feefcf635238bf4a","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.3-alpha-1.tgz","fileCount":121,"unpackedSize":348658,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeb1ITCRA9TVsSAnZWagAAaNQP/R9ROA2AekdZxMccOc7Q\noq/bziqOJDnsst+aezH7Kd+XH8K7kjIMp0or/F2QK41cQcQSlySjgaUFWs6i\nGbdSviQfOF3drhnzSKO7Jbs44MARgrsylqxtCfOAScm4rHuMe76FEUY4CuWC\n9rscl3qjCslLHkC2FWfXbYeoSVinMiLWIk9pXeuoVvWJctx2Izws/MeQwHQT\nXYxG5SaNCLeiFOJSPi0ttAdNJPiJDX39raKgTFyP9yipgdHh9sH9bHZDgJHd\n5IQ/Zq7ULCdA0BSZDXPO8Q6iXg5v8i9aq+R5mi6TR4r7mVDYlKTJCwX39JiG\nrxeCyBaRkuyFqBm9wur7MdFyvW92JQZPWYQUvHOWhCgS722F4HTTvztFgd+/\nrYrsVGjD4HO2mQQM8i2YY8Nzy26DsDyJqHVSlARBpaBc7STkvZ3gNzw6wHrd\nufkvxiFdY/MUAPJ/lSVNl9fRDz5GOT4C24jS6ciWRiFn0A8Gj6KrWSORuOsc\nL+9KpbPqQnRJ83njlpM3t50pqUWRm4vdGN3zQDwbp0jKPq/t+bbxWYu6NsjY\n2ol18OdrgyoF0TaeZdP8vgaocMdNthvSVDjuYZ+bq4TCpx/66aEvQEnkegLT\nOKtArNwYkuxMfhPxMlFI028VZuq2Cie7AYxnwPZRxRmUBNvojcuGWxqU2g0X\nexE7\r\n=XR/9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGy5ieUaeXtZWbQXn97acItc/Am893MZwQE8ZQqSH53rAiEAgPIUU65kkCpK98UgwEKnSwrckOky4fjO+6KgTzMIXQs="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.3-alpha-1_1584353811259_0.8022024144136197"},"_hasShrinkwrap":false},"9.7.3":{"name":"micro-kit-atlas","version":"9.7.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"5feb2786c1ecc878b602186c049ed6cdd03993d7","_id":"micro-kit-atlas@9.7.3","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-/7K2EfsLi11rmcThnM/O2HBhb1keGYm/t5yDB7/kjRyl0Bgp786yNQQ0qTEHPeIGHtIY/jObIQjvCd/L9vSqiQ==","shasum":"05b5cdfd9dcd0e3266ac0276eb3ae9351b1ee12e","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.3.tgz","fileCount":121,"unpackedSize":348650,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeb12BCRA9TVsSAnZWagAAFFsP/11gF1ETmWaJ3twpta9y\n07I/ijsL3Duvhxbx1Ab17cwHVdiK2uS/bXGQxBagkwoXiKfEMwZCkRJ/IZec\nISRJDjbVPXGT20DwZIYvvjPBHscsZddDVch4kFDVd/7dwwDFrT9KFNQyydOh\nMc5uvIULr88blVKUka5tT5pHbxf81asFr60khb+qRhjhz4ROIVqW5kYIU2IC\nJMRH9c4GEYMEqPsnkR2+InIn1biXuavIm13Ro1ztbdkzy+4U0HDpIp/Gc9U7\nVfsT4S8DQVANobSdaWYYdHy4kTwRwAZHGWu00wlJ70MDE5U+YG5nHpzd6xKP\nN1qdBBHRGcQNL2KlEqQXvJaD2WUD71pn9xrc1vIYVoNkDGcPKxCX/eAgggQI\nBkgOv6o16qbra1gA25GygK3RmOQppxBvtpDuWlMdk9LdyKKRP2485Sao5Ip5\nTkDF0Hst8B7y5R9/AqzdTahF4BFYkvE0pvTYktGSXaBkdJVIp32x1SSEYkf9\nZNYBDVaq+hXdf8E8Qys9rqbffBkNEDEXSU7TbZxnpjwsEoRjsf72PpBa+9KP\nUrQeKJvE0R5sTTOsPWW+4L07b3gxyJBKCPxgCdYYPKaazQpTubIc49zLM9EW\nBsLXVpVzzDhhCX8kxZo43+9v5F6wxqEfZz0XfvOMiZNTeTZU4LDzL0xMPmUl\nkHqo\r\n=FtoR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC63bu/ZUwvaqvd7UmNaH1qa+7L92Yitx/r6x/txoyj1gIhAKX2iwZzUa2/OLACbBfWEWwD+K7siB3NKRyyIqaD1RZy"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.3_1584356736732_0.46669938453047966"},"_hasShrinkwrap":false},"9.7.4":{"name":"micro-kit-atlas","version":"9.7.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"9a2348db8b6e61c50b3c21acbae807feffb242c8","_id":"micro-kit-atlas@9.7.4","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-U70zCXKVrmTioOTgmaF7OVHNlhfY8D3AUu6Nn5p2NUBqTmzMwPsu7HSRBW/VYcI8T8y8aWMGJXAunQli/h9Tlg==","shasum":"772be178d7535cfc79bd766c0872fb43867b96de","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.4.tgz","fileCount":121,"unpackedSize":349341,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJecJoNCRA9TVsSAnZWagAAwjQP/2VDFGMgTY/6AjNgMDmq\nfDX193F2zkrM7Ch/rnpVzcR4knehP47wdBMpHQficAkSETLB+pR7FnhC0LL7\nWWBE7MIw7vs6Vk3u7m6te4BuB6I58tiJxMOA24ECyXy9qr16N0siBMftqe/s\nqXAON7Lq7Ia5MUNn6059yy2NlOzjiewtUoBt3YeZ+uoL9GcCV+oF1806+4Y2\n6m6yHMYTn3P43pM40BktfzxFqFa6UC1Yxik5X3cHqxLx/1bkvX7QqEbB4lJI\nrrCLMXRbMmGxcatjekQaS5wGZBBPjiIy0tlkWMwQlyqpSQml4zgZyp7uROKI\n+s9r0zjhustQY21U0+mpqgPGPwSbrdWdPEE01oza3t54Ojv7JQMygxDZr9p5\nB6f+JO/J6V6mnQW/WavyMfsGmL85RiszSKaldY7lqwvH606yNd2s6Is5N8yb\n+wFPtJ9UWPielyDnA3DHSThEskmrEX4WYGWf3d61aCkx/QdDSLiU/q9RgSID\nUCiiXRiKsnBcGcP8DywBdRzygR1aLW6gDJuVNN80wBNhY2OM2Jak3Sa9uCp6\nYhkckgMPP9VVhd5MZhkONwjcVrIVYQrPcWElrcKGiF2hWvMqa+iggMpEV0qz\nF5NJAKlrd3Npk5Ta0fDhiWCU437U6Km7Sc3WR+/tAlfwmc2jdu8bZK+wkdyM\ndkNI\r\n=EKnf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCw4FqBsBnLnbuQoUj0igzEZVZbE2UkiB8LVFVwE/5eowIhAKalq26wrZOYV0/UhLvXYpW4tLZeOtmhFJbWRAgOkTEV"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.4_1584437773241_0.1349825896400716"},"_hasShrinkwrap":false},"9.7.5":{"name":"micro-kit-atlas","version":"9.7.5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"c332fb065c3cea51f74eccc3e9b2924dd7dd189b","_id":"micro-kit-atlas@9.7.5","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-XHkdx0g6kn28f3Xchmla4qebfeVmTF3+GkovBgL06hWwxOzpyFgqVVKqGc7ZGgaAQKpiz8c7flqlKhe8BgnslQ==","shasum":"ed38afc5e60704459cb3bd1a18f3b967aea21f73","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.5.tgz","fileCount":121,"unpackedSize":349344,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJefef2CRA9TVsSAnZWagAAKFMP/1X1JkO40gVf/XkOWVMP\no9MaoBYur+bvCRC0y4vGlak5wPnQjaot3dOBT6WOJuCaKrT43fjAwiJ4zcXb\n6HW3MU6dgMKbZfjVBNbNq97pw8lsgk+dW15zdaY6i5Ud2/g23f1OkYq8KWVg\nTy1RMzcg9zJ2XS7fC00LhcpAoBcQP5k/K8WQJR+/DFqnMFdBBB0VccVXIFbN\nSOBoUzh/00GP+WVz0qA8fCk0fu4YLFZ6rXW8s+4NtHeXCAqWtmBS4WisskhR\nskw22THt9ciINsqHuodOeVMJ18TOmd4Vh4ihEV9gbsAJSQuAvZOE3DY1jRmI\nbZd5GHrYBQsogub2VHFPb20zObxMywjv8AAMzlD6KNd1WLKrocdLW8kDkMcJ\nDcaa5g0y8FjGxfvUXyM4BEXgqITrFT7iQzAqVBXzIGyvHZumKqLBOnuJeC21\nt0sLV8JDWyDFQ+WVNEZ/02Q+wuWBv6ZfNYd6htxlVmoLGLH2fJ4Q/YDglbrp\nTK8E1EPgQK1NvsUoAu8akPD9dLpNjswxCeoYejjB1W+JFk5OtnmqUB7QEoy9\nXLq5ercBJ28Y4DXQn72gA3fkEb4muPDGx1TQvF0GxE3dEbd2LvKCoOyyJ/Jf\nlsl3rMQ60DvTez0VJEgcPdQWiwuHOBKoyMm50eihi+HtHLLoLdtjrSjPIqeT\nIBDz\r\n=y1tE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGMZlCR7mL0P49KejGLnl3N26uQavglnXhnDBKPd0HtmAiB3SwhZEzPUaJRqDc3pUa4xyZnXjVr8YKJQOGGBtJ+B+w=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.5_1585309685770_0.3944038546274984"},"_hasShrinkwrap":false},"9.7.6":{"name":"micro-kit-atlas","version":"9.7.6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"0a1f5d7e37dce37ba4f0ee19daf5cbc748fe747f","_id":"micro-kit-atlas@9.7.6","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-6NHqX8PoP0P9YHSYZXMV4boppJzU2BFBmiIRHgR4BZXnu8MWSKpv9bVi+9PfiFabIxBbIeiITEc5/JG+YC7rPA==","shasum":"125171d0390f811fb593cc45d7eb8bb1a13d7262","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.6.tgz","fileCount":121,"unpackedSize":349404,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJegx3XCRA9TVsSAnZWagAAuYgP/1oWnZkdMbGUynLhkgj7\nVRkVGRYPYwg+vO1zIAsskOuuQzP+eUgEG/hhf9/hdsqnGMO3/BR85FzbeQ+6\nCki/feEz2yEiaSoY6WA8TvbUVJf93BIokacTw/ofHTuwKFvMBUhMazHMbuKu\ncfhvKf2cfwP03P4jdmdkEwS04q/dKOBAxKFCOdk51zuFXVjrMxFmo3/DUaan\nZE7IniSPo6ITGcalSYEU74AAEk7RGkdaAjkWyF4/KJYar42PFZ87Gnc2e+vp\naPzu/71qObM5OzheVk7uvxi+V3NvSZ3Qz2p4hYoLnKYScA+Ttn4mPrlojalL\n7CNKRwXk3y5/8D4tx9iJc/TXWWYIc49TowoZwLDKRoN4X9QeFFa91V0WCOGW\nThnOKx0laA03rBrjgfNW0ZzoLzcWH9jgTuY5kw9mBaPPdvgvA1QH1pkGMY3p\n8gLiC46kODtGbXZcbQiADqqMbSwjTJwCUOGGzb1YeFCHxX1Ckfm/ImFO+2eO\nRvTpEECzpytwfJvCJn5IxB9R3xSGBysGfpSc1EGvfv8Uhujmb5j/s5ii/3Y7\nppFHIajJwVtkoHoPXAyVImJbrI0ZdAZh2USZGJCkiAWi7vdbHA9bpOi8/dEt\n/2YM4sPoiWbV9Ot4T8UBTM+vBUbkDVIHKLxdmh3QAtW7jDM42xF7GSxyISoT\nTkqj\r\n=6XvZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC8eJUpIG75GGbSyioLrebZ3ueZalSzdU2Ce+D+P9NAkAIhAP7Z5HJ4NujSxXV0jD5Vg/ANtHWc5jPVi52McTS2O7jC"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.6_1585651159097_0.9239418758537099"},"_hasShrinkwrap":false},"9.7.7-alpha-1":{"name":"micro-kit-atlas","version":"9.7.7-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"a1306d63632a48b1beec023bc42e410ad180a01c","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.7.7-alpha-1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-2kEqP43LqrBPN+/Y++NznOrxHCkEMUnmY7rfSZ9zz5wbUGwQwwhSRr48BRp142RFxff6mcILQAF58n3+iHJXhQ==","shasum":"8f1b286926ee2272813feb1e814d427049e4bbc8","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.7-alpha-1.tgz","fileCount":121,"unpackedSize":349470,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJejGmyCRA9TVsSAnZWagAAHccP/2ehDItoxa02rq0E/+A8\nVM6UHF7dNU8rpDb/1p85h4ia0G2/wBPjOupQ7+R0KKivQF+jnWq7CkEuq+G8\nq9QdSRcyHwx37DiLn5nRe0ddNIC0V+IdtRCaGupJrJzy6zsyzST8thaimh5j\ndEILvRKS90iDTZlEaFwZgLDMVmg9R6CheHRFEF/uxK34/J8ii+415VHkCSzT\nouqpktLQb08K3B1EzYeD3e+dgUCeA4D8Sxhq4eMdLA7MwGj4qReWNgVFr/ky\nq2R356OlARDjyfz+lubEh80HVkH1DYLYBrl9YZzZyGVgDb7dAXVU8M+fs4JS\nuCnabWAKXdqrfS0YdL6zVi7Vt7xzNcRamBQ+6lzoz0VqoYL2bYyDs4UXoLxx\nfPWK1+5jX24SGYorm1Wcv/QDyAtLWyB8buxBoCNzYm6Fy7Bu26sx6427vbsb\n5C8nIkusDlkGfZfYvyK+O7sxsLPzcmaU6aMXiu4i6YZDQdadkW5s6CWw+Ct4\nk66Mh2+PsMpByW0va6F0H1zp0LvNU3pgjT0NsKhnEMdkkQY2z8VIwEUcdwLr\nlt2s/9LGL3lx3fRdf+CMiHOJnFN6XrJKpxVW711HVlQ07rXEPankJkS+yy/G\ndSPmr5XItmsC3bOxqiPYdLNc3WoMdsZ/OXXBjjvvlk4yMUqi1nyz8xs44mj9\nOWOU\r\n=mV2C\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC4xMpHh9e0m5GlBr+AWuf4SuyBO5RqproamK1fM4fILwIgJL4qHcTvZ3gUeP1sTGYfetMhBC9IyezwLqUXwaiwA7w="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.7-alpha-1_1586260401935_0.7141080601927838"},"_hasShrinkwrap":false},"9.7.7-alpha-2":{"name":"micro-kit-atlas","version":"9.7.7-alpha-2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"2b488765cbfe13fb3e1ee6c04d71ab716ea777e3","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.7.7-alpha-2","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-9OcoBWqU88kduyUZq4VLtQk/5eJtpHG5S/esMNiGqxm+ICnObOtLtse/h+STDnTfmnHn/d5ZVK6wD98QQ+lbqA==","shasum":"f75e82dce4cd46684fab5b40457ac6b17f942fca","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.7-alpha-2.tgz","fileCount":121,"unpackedSize":352354,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJemXT8CRA9TVsSAnZWagAAs3IP/ioXPHMELTOiaS+kcmDr\nt7vTijLMAmDCi+GXcX5KPvi/BIyDJEyQ5w2htg7ol7Rt+r5yJB8+0s7WJ5ue\nWM0vdtt6QJkHuNtFbLDC6aYZa6vgFDQd7HGw7Nfc5zh2/AJjvxO1KWC/AYn9\n0qVuhP9djMfYRLAPpwPywPIagAjDFpJKw6SFaViOqH9fItDH1SbKS1Qvn2jA\nuJ4lzR+urYVlHutdqG62b6riJVKGH23KBvWNXFGXaqkJjji1/+HESZL8ztC9\nwCf0OxUSpwHCmZpPSsyvtlSZUyjDqcQvzajei4agO5eJ8Su2auoz10QExKa3\nV/NQullAFJEQxvu7tWzHXXpQwbBB4UVgoD8h4pd3I57KsrqXhjENZw0t0wsv\n90YYgv3JOFA6LQ++QYHbgq2SwIpfqDchTTnXJSvSoSaPOTWPgK12pIQLdgOD\nXONRSlA44zuwzvjyZcX/6YbFOKpSxRiRryrm7DuLGfWGueoIwlAcZTq7vbKS\nC40v/0ib43TlXSrl2cV9lUkttdbQGrUESgUIWOD2nderL5KJVZN9Rs1tYmH5\ngJuyFLaY2FOLDHYfUrU0MMrEejsKTmYNneOYirIV+87XWkvnrxG2LqxCO2JQ\nOkMWk5yeQ6MttUtpldJc+sq3Acx3yWu7px4ZW4bQg0QfuQVpTTc4VD417VfN\nZOdV\r\n=XvOt\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCNrurYkMomxf3HpzhP3pAdg8g698qEIuCjEQdjt1lEvAIhANjkMD8f3Zi6ND3UFm9HsyOuYsNBWZUUUmRbfihcjAGw"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.7-alpha-2_1587115259635_0.48332202705823124"},"_hasShrinkwrap":false},"9.7.7-alpha-3":{"name":"micro-kit-atlas","version":"9.7.7-alpha-3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"17f3a2dd7f9db9a8e8fa61c2800a54a49dbf4540","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.7.7-alpha-3","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-VZpOI/hRPGzrpH9k9k5tysdxFmC4fDP1AL42T0m1N1465QHEMxnhMkS0mVIKcu4Gv559KHjbTR7j5OoU2PVDcw==","shasum":"1ac1282f7ceb0604a6a246964d503f070e00a8b0","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.7-alpha-3.tgz","fileCount":121,"unpackedSize":355303,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJencyXCRA9TVsSAnZWagAA0fQP/A8qcHvzz1nndb5X+udq\niVEMFLact7Flks2baJ6BI1KKPkH8vh4AZgsnoxiuH1RpIJ+BLvYK7qiiwNIi\nQVM4/+UxpZlzSQHkDsQ7qJ842mO92h/BM3WsGC1egVa5AtgkJp56SVjHgays\nNJPQQlEgq2u8rkZMwEwwVktJwKHNe6YdZKItmnUUhArUFrXxpxtxNsoLhnzs\nxd+wgNsEvOkjPB9sUKKhm3mrePInnKFSMRnZ4LcrfjJZJfBijHHwikpCvOu+\nkeYGwNTUnWgUWhTREid9iTVO8R90XJx+1P54QZLpbrKC2hlO+/dV2KbFchm6\n0sRyXMIfuK/KiXOrxmptvYOQTuCoEDBZPRdnHP67BmkpJAHgeMJ4yDJp+/Wf\nnAPbgV+jrKt8tUGm20opS2CaVkGOA3DCYwM5IfVIZI/r3ban0045COSdUf8+\ngOFb/7zsVLXep3IzoqoQ8KacXCzSHzRx1O7d4SVylYF3zIxf/Pqp4Z2feUhu\nrBihBjy1IrlAafFYtGeD4y6oJGQuJgH+hSCI0Bu6aRTze9uLe/CT4yf7Klm8\njtHCjJURIn5ahMBhjiyY7XWRgiSgFYk5+wdEvMDFMeMMr6/EZdJgxI408aR+\n+iJTjwmcwfM4JFY9M2ckfA6VFQnbJAQD6ZSkOk0W6E/VC0QJQ/SNPwGgHqQB\n1xAp\r\n=uYeT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCPS09FW3Fypg9LyOjADUtZvAoXwzt5De7D65oR5HImdgIhAIU6LeVKE3yI5UzrIkIE+diqaZSJEehttlpOeRDojcvq"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.7-alpha-3_1587399830829_0.8004270883838738"},"_hasShrinkwrap":false},"9.7.7-alpha-4":{"name":"micro-kit-atlas","version":"9.7.7-alpha-4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"970f4d7a3f3a02c1bfcbef8ca94ea193441bd041","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.7.7-alpha-4","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-HBN6BgFc2pBLq/AOoYmQyC5Thlcx+QFKAb3w0LxuLZQaU5tOMgn1lsEBxhoxmSXn7TpnzdxyT7iOrXSpzop6TA==","shasum":"30e0a265e51ed25d688f9c2dc5f511e9a7b44318","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.7-alpha-4.tgz","fileCount":121,"unpackedSize":355339,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJendT8CRA9TVsSAnZWagAA83gP/isi9+QSwXY6pn1ozA3f\n+msrL57yqdS9BC4m6QCEFvvRIe2Px/28DAfD5ukpaTKoHGK2n08ICtuB4eeO\nRYtV1KeKb+E/hBAqq/sQRkNsnJW/GcvfatjSTiGo6yimwP5MWaazCmS7BZeQ\n+SC7BofUwORKd0MyEk/sJanxXEc2MOV2m2WPw4BhocrM+roFtJ2bktlcDX9m\n0Hhw9IsyW0W1rBkfOQs9pIKnTZRIUC2iMlJiYvg8tmJAX/674SOa8aqM14/g\nWrYA4VgjIoS/LynT0AL+zTiL+oSle0wxFCiSFGAW6HcqqJTdFvIAKBcv508t\nVEZpNCgAMZLX1wPEBQaStSuPJ87RCpMTnNZCmJIhTydXN/efatT/BiJbhh+Z\n8+8qj63756wbq9SMazjFYF9XjCwzuyAQnGERcGO3A6TU6TWlIpRrWm6Ulbkj\nGtpXKgEZWmwQYu1Hj6GHNnl2O7gN/If2/Qw0lVVNoi/3zs+PQOXQzg8dkyhx\n2+90Z5H9Mw79SrxZ1Ug8hsMNLqpIkzFscMFPutiIQzSMIV7FJlwrqmqdo/xc\nvCQ7gaznrROJIkIhdhyw2crmNJlKwO/eFlFZiw8f1Y7cbXU5U+yYkv9T3Ry6\nRA9y7+RIQbNC357/zhV97XWmaxYycvKih3oERGLX+2qgnjk8JBtNWjQqY/h0\noFZ5\r\n=j1xb\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICmiLUuHyIq7Vtle3+32xbSbsoXI2NCJDFlfQH9mGkEQAiAOIKkeCzpaVLbaSzuxnojfxK4JdJ3nNSp3knGbFsDLwQ=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.7-alpha-4_1587401979737_0.7326379909133878"},"_hasShrinkwrap":false},"9.7.7":{"name":"micro-kit-atlas","version":"9.7.7","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"d4caa172624c361a53fc5af7b56aaa4e0396ec56","_id":"micro-kit-atlas@9.7.7","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-BWaFDU6ZMTgiky+MjR8k0hJwQBlx0bxdwxIv1KN7OjQzwkAXS1ST0BklzG/mNx354Q/0gpiISBcQHXK07XWxBA==","shasum":"8e79aba3e892b616632e851bd1609056363bfac6","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.7.tgz","fileCount":121,"unpackedSize":356457,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJesIR9CRA9TVsSAnZWagAAxboP/3au686bP8WH5BsQZQR/\n/RJ28eC29q8nzcQfo6KAvdESVyXqsypUqnxA8SceHHalJA48CA6d4SX1WEmY\n3RB7Pp5NYLIOEAXKcltiGNLILoAfmCcKWTRsgsCn6Okki2BEDAuWDFlBfZES\njtBR4GazbgCCHT9QhPW3KKvfPy018AtU+amNURCVPQVEXT15FtZohOvoPIcv\nhE0MnzI3CFX/RGJykmVF2CSEaFZZ95hpqqE+M9GXkQAzBXxnJAPhijzznfeY\nXVzZkdqtmXbm3fNtySd9ldKr/X6AtNT+Zy2HCchvgJ6xIzsPcb77/K2S/0N2\n1fG1ZrUZN4hOr5H2x+kJUs0DkVbFY/8a7YjEaUO1uDMJn3IzEBLfIj+IiSXI\n6nXxFF5lUBw0eb6QjW1jEMWWng8RPGBpcL71zoZ8fTT2j6SS70CUkusOPu9T\nPQEdnT1X8IQJOHqm9vDv3IKuoigJvFiHOt2O/rVI6P6hLjQxJDDWOeRpCu25\n/AxbIYl5o5Msdp2uxiXpzPwqv+NXQuWrQgzJdm+DbGe5JKcoigTkhxjHsN1q\nssU/6J6K9bTf8HPVAqijCijFrU4Gsurcq4dIr8XSrbqf4DadltcJ8/Q+j8QX\njIPFUk0D8PcTGpbdDJac7AHLteytyP1BaB5XN1g6vCkGIdydDdklwysQGhub\nFr81\r\n=pUav\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDRg5JhG0N3ZSROjXxXwuztsQ4sK2dS1D1Xa+3158ILyQIhAMxv9yT0C3CWxJTUY03Ugr1HrbvhrhNZqolUDSX4AztP"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.7_1588626557114_0.7712450570119249"},"_hasShrinkwrap":false},"9.7.8-alpha-1":{"name":"micro-kit-atlas","version":"9.7.8-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"8e0dbacf11e2b822fd3202a5d5005ca0ffbc28fa","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.7.8-alpha-1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-6N49wqi6aHryB5TE0kCxBufWfN+nlbrvzVZXCAu+Rm9U6RvvvPcQtG0cuOvIi5Z7OlnXN3m3/Q1xFWQs+pCB9w==","shasum":"0db57efef9727a61becb4a348f147d2ecee91aed","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.8-alpha-1.tgz","fileCount":121,"unpackedSize":358647,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJesbRzCRA9TVsSAnZWagAAlzIQAIPiTgYwrIVdD1xNwACl\nbAFM8vPIaYtxFYaNMFRaSoH3zH+975IfabBlUyAGzhKEF4mr/ZOikNm6Vbn+\nYuVTnJereEVwWjmjnQAuSCiffE7W7yJo2Uu48sEl6NAF6ZmAG/u3N03L7DIt\nCxHXes5caMwjcbyXQiC5Cr4Djpw9Qpt92kw90wdL41/GD+tXWyk+Yp2IXFDm\n71JmBuUgLtrrjzXpte3wNn+gYmFwQz716vCcVGFX+SmeB0wkLZ6WI85YY73a\nArpPBlFG1srVQrqYNJTZiyQS2Xgrc5wfQmyAUWWF8rfDpTSaVC5wIAeC6XNw\nBAxRUA1hibObIMhdZe63NH68ykHQR4C1bBQJCuMdynSlK0Lcq8hr/q4owyqx\nN1j1wJqyqX89QsVla28Q9U2hKEFumMRupZAJZp6h3RoLYG5GWLz0GK0TpSYw\ns6SqtuPJs10+hz2UCQ/jAL5Vke1F+ycX5eJvYhgY8A6Q4GvgGlANxqlNPNx2\nR5L8xd9MD6LJXsnaZJZVsvCHdcdxKevgbsno0Bf0YKGpsd+P8f24Ohja+oD3\nY8b2q4bXbCUax8Q5JC3UcHJ3jsXnqL6mvftA5KBKKfNDEsIReIU0jf4Kmj7l\n/rErBTPVG7LfrSc9mdNiDra4Z77djvdCso3w/gp5Qf6kHy4H3W/L7mVBP5KO\no0Dy\r\n=G/ul\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDd32/fO646Oetigag3u99cxwLJ36T5uUtiKEvQjjs7GgIgLdj/zVS/i6YrTiwtyLMwLUCM4BHpsPC0AXNVSKfS0Hs="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.8-alpha-1_1588704370898_0.12639114986933486"},"_hasShrinkwrap":false},"9.7.8-alpha-2":{"name":"micro-kit-atlas","version":"9.7.8-alpha-2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"16ffc4355a4f96de57d34c28e3d29105126bfe23","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.7.8-alpha-2","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-pgnLJGStcZQhTuu9/oSrh8nqCZyTM6uqI/QwFWttIV2C0FHbBk7XW7+TAW8tBMxlu7faOZtScil+RbE2sE5jFg==","shasum":"f1ee7c4999ba6c722947a7ef839f4f2bbe1b6515","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.8-alpha-2.tgz","fileCount":124,"unpackedSize":359646,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJesbtfCRA9TVsSAnZWagAAKI4P/3AaUFporNZjiRwM+f9S\nmvdhPwPKy4ujWsOSV7W5tGhCD5jJHo4nXU9eR7sZA8vNT3moj8y7p7rc0jPz\nwbWySsaXUotK+xFijLk9RE3vF6/XGguRnT0f8paqIjFGHKRRMWhZE4SC+94s\nNz8L8lxvg4axLEp9bnpVrroK+DzDTr5Kc9AKoBCoTghGsoQuM8Iur1fNTSd/\nXhOTrOnKYLXfqa4NQ+z3ytUfvz7H0VgRET2n02fIX5syBvSblHB/BSt6a8OS\n71Xrk3Luga95Tp1dvzDMP8oSrKvIsVZ9FH33gUFEhR2n7kkWlRmnOUVdrQDq\nPytTgH0qzsIT7pQ4QujT4DourcuCSJryb5v9TFcWcAHgpirM52xXImrXgGVb\noSVKFztCJI/xlbnwgCvsNir46fGSlo9ZfTzUI5DqtyTZZSSQ+PUwwtTnd9JV\naex7NWRMpd/WVQH2fPpgkvB3yVxxKFHGZoK7qD0HmcKULopRnkqT0IoHhBM7\n8mki+lTwRlzgVD7mXxpj7E36BzsV89lPIDcAp7vSKIfRRFZAhCyyfaaBczCM\nLWkATt5FjDIYO0hzld4PtYI18K5ZiLVgGTFrRlX8hhuV2rfzk+DsPzSLPf5O\n+xxgmQhqnguXuztnCEnuRpJ9SpahBwn4DWUSQvKr7zFIfT8+w0iCxyxxzQAt\nT/9y\r\n=Zy6a\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCFj+P0Ntu1V8LlQR0/Xw8IZ1jsCKq0EJT5kW3dO0b1CwIhAKSRaXWW0kUEdmVmfXhisBUayWG0OKvGGvb4KkTlWafq"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.8-alpha-2_1588706142962_0.4359535662651264"},"_hasShrinkwrap":false},"9.7.8":{"name":"micro-kit-atlas","version":"9.7.8","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"f6d8adde8ffe0a6f6586825b0df5415594785586","_id":"micro-kit-atlas@9.7.8","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"nejc@qloud.io"},"dist":{"integrity":"sha512-w3sZoDhB9w8uVWVJg3ZNaNRm/aCqJgvkVIHEMkj2Vc/mF96ntAA30A809FdeAhTraBwAp4ZUwNfYsS9syQLBCw==","shasum":"64e3613251c7e8e4c03a0ca073a27896be3653fd","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.8.tgz","fileCount":124,"unpackedSize":359823,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJessPMCRA9TVsSAnZWagAACREP/i5u+p8CD0Ub9xWw4VV4\nUBTgxeRPDqyTPbjBW7a9af9JVjLFDAo6VoHUtMOMPp7y5XNQBt6MaQFjDn32\nve0WjqMzkR0VsZ7Vinx2/cruARHIS+fsFnI9wr9rhndw+rkyAZ/FVlXYG8vd\n3XeLEvJGZqByv/LQPZte65/I1/viv8j4S82jjIyl0U5xQnjA2/X12A5SpNIq\nL0MZF6shVJV6jnJlje5/hyu6wrhttesfhe3S3OMzd6xaoKnB4pvofrBkn8ic\nlaRVbDiiCGJ3GUzAZ2tx55stu8IU84YIoDMvqbHwSmNcTyI7/LOXkJHUmSWw\nNdJXLrBw7gjpmR94sWIePhjFtsLkMmXaNKgN3V/iFoy8CNzkKvladb+F0NJw\n66SfN40slBA60M0G/0KS7BcF7hzmFuUfEXiEcVzvuLnnzoaYwho1hQRh0iFz\nSI+PDAjdk3tWJVZu+3X8vGcI1AZ+uOpfBbeCczIcZ7evhp8nfb3fxk0xE/Vg\num2m0zHiqX5RtfB5Lr6Ln5flH3mug0lmeFTzgU/CjYegkOcVaWsbj1nCRfWr\nazPsLkIOn2pjSwFnUBhdIzQA62kZ83B31Oy0NXBiufp2yA061XZv2U4Gsbjo\n75awzZ3U+RFAm+fwwGb/iyndGHZm0HUcbL4qpIcJy4Xj+5+XGMeX6oH694ur\nh+Ef\r\n=v+tg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCaHh6b19ZvT5zcL5tycWrxqXmbADKD+TN0e9i4PJwMygIhANaV5TPO0rJAl49h8T0gjcQM9wOe2pJfKbKQoe2E3pid"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.8_1588773836033_0.10638794407126695"},"_hasShrinkwrap":false},"9.7.9-alpha-1":{"name":"micro-kit-atlas","version":"9.7.9-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"1d66fcb8913d42fef156af466a4168ccd046fbfd","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@9.7.9-alpha-1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"dist":{"integrity":"sha512-esipOXZkVS3NCsJR1i5X4yxOZsfMHgxtcfUssDeDxywLEB9+W11bIMCg3rM5AK6vQ9bobZQDCW5OV1hhId+y7Q==","shasum":"7e2f0a651bd66f3bbff3d27a0ef106db508b9f0e","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.9-alpha-1.tgz","fileCount":121,"unpackedSize":356980,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeuZsKCRA9TVsSAnZWagAAJfYQAIPpaqAWSBK+Hz0h+hjH\nzOB232fN7sxh6MMIaIHdRWuGsK+yqU0aZ0Eyf2ddjJIEO885iff+Lx0+1fWb\nDNWYohqoPpiREHJ4vwRFqtfbxNugcOWp15mcrug151qSEEd/Tt48TnghTzh4\nzIcK5aX2voQGaDWTNu7cUBffsMFKo1TCdHKQnNFx+Hay6WvkqQfWJjiDT0aK\nGkEVE+28nozeFMqiZ97EbmV4CiJjo4RJuKz86SfMOS9zqHMmoGkq9OJWgIa5\naVeSq8G4nYsrUB7/517LWaxWZq99AuxQsmxkYRbZ3gZR9UJYs5iaxYyODj81\nLIJQRgtP4At38dSKjqI5oQN/Rqbp24Nn+ckLA875KiQFtqa/Qe4NmRw/lu7m\nYWaae67mppLNJoDgOaDrav12YWL//2eQdinJQWC3iPSXglit4F92oRt0pd31\nZseBiWm28dXxAJfyxurMrWavzIBVhc+QEqAeUJa4gxXHssQI4zZyMcyOTnJ1\nkauxn8qlQ0N+l/nItNbgcCnHKFaRxLCXEWTQfhhzJ94M4vzR/sq4N2Wf68v/\nisIKXYJ0BzwQXNIXUSEbiEL4X1PsPKvWaHaMOOsKK/mGOPBHVdSeuye5nxFi\nu6ebYRYD7EEQvS3lHUr8eAX982qVKoqf1uEjcUmmTfx1MEqn0nFebUw04Tab\nag5p\r\n=MQB2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCi6SAQS8jAxMKPynsUeNzvM1vkh4+kKQJx0l1ihSP8/wIhAJEgLA2ISxlKmH1hknFpVLWgIaFTZ12acOomaE5cE19M"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.9-alpha-1_1589222154021_0.6716054387781056"},"_hasShrinkwrap":false},"9.7.9":{"name":"micro-kit-atlas","version":"9.7.9","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"dacdd29c37180e335f7a3f15ef4583a0e3a7b375","_id":"micro-kit-atlas@9.7.9","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"dist":{"integrity":"sha512-tFcbN2mv/T21gjqluNf1sXo29Hxz49ajQY1DbTeiF+SW1I/4qvZ2RZDrvimQHkSymcR/G+uayf6lt8i9GjqCHw==","shasum":"05bb5850782695f33978ca499fd9a6abc17f8a03","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.9.tgz","fileCount":124,"unpackedSize":360338,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeuboDCRA9TVsSAnZWagAACIwQAJ1wKOPLkdRn8ifD7gnX\n2hjbdOTH/pNbCBzyUc6DHYgcWaamslpRlMhgmLBg1R26pBkSBw2WH1kLTjvE\nlqUgUTZA4yjtlrb58vhGfXXTeGX/S8jwH1QG2ZdYIRdiFSDLSSm2cJjJOABi\nPMEp9E4x/FF2rB+oBjiLx0q8fCPnhlTPmSIpaCKQ0C1++NIepc9AM49coq3S\nWT4Bk51IB1ch2mY6FutktoaDIFmj+QzQlYChQKmkdZjTLJglqNXc/qg7U4w9\n7jKGwFlZtXTxRiAe4dOGFrzrHJwgn8kqTpl8LUl9UJlHqEXPFnVjbyvoKbDi\nnIjHWCySTZll0HM785GazwlceGm1MH4KSylIx9M6YqJ5PaC99ZLkxwenr13V\nGIDDd3zGAps6QOppfssGhG8G9S2KfNs+TjlnU2tbaO09zcPKdRil6J9v6iu/\nTVZ6clvE+DJK8qIPeYc66cPHU7Lf4ajzuwTukqu5BJPvwjeKeQYf4aXFPcDu\ntF7ppnmOrhGny8PrBOmy4fTRTc2BcjqUyujUtBGn9UOKy18ocTnovBMCMKUK\nuLBN9FRbYHHmgHxxowUL2YNHV0vErpnZ4c5HsbGAMWEEUUVAGsaTqgBszBrY\n3Y3CqZS8aqXJPrCuPuEue/h99Pf0K4dlnVltpmRrlD3YLNd9x7WZ4myzuh2U\nQl/I\r\n=9LIi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC09Fay/SjIsgWm8/PgZvp20XBJnD9JS5zxkrMI9G+KBwIgSmishRF2QjaJd4iUYwSzobOXF4tytZGVZ2d4GXUwcvc="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.9_1589230083023_0.5012717691163304"},"_hasShrinkwrap":false},"9.7.10":{"name":"micro-kit-atlas","version":"9.7.10","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"fedadc7b4babcbb506c698f53a023cdc6407ddcd","_id":"micro-kit-atlas@9.7.10","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"dist":{"integrity":"sha512-lj30HcbIVinv9wphughFndY+i4HMMgAa9Vu5OFiGMULLbagXLLW37xNP8eYLcekvm0Xxf3tcZU57f3bH+rsULQ==","shasum":"866e73e0487a25b6532588500072b9f2d12ac61c","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.10.tgz","fileCount":124,"unpackedSize":360593,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJevnP9CRA9TVsSAnZWagAAKh4P/1+9onUDUcfiNYIcb+jX\n2KfojHy6Z2dJGC8rVfyGu4ACXZ96qnvoT+rIR2EyXoBLxgRKi6WQvuaV/D+t\nOxiPEsQSUENByCpO/oKrcKOmdUIuRyfqdcTVdfu3gcivTQBvek+jmLf/Z4OW\nkjZ0ItMVUEiEGJu3TJcXu8Vu37IS9ysUxnf6+MCbdF1NKEVLH1WcSEheJMkP\nEQ+fayowIIwd2Dng0HVGuh5VvTlVmSk1gLnbekHOjzWYeGmGWBzUJes2OZmx\nV/x7Zezi0c8JcpQ2axCX5gnJ6P649MU9JmlWT0DVJZtY5ihAFYtH1pp8VRNh\n54/6/bLcTw9PNkA9HYyfmeRsbTBj5tmMPCJcE1kb54LaXfzjtv+o5bG6E18r\nn0N/YoMfhujVnUWkUfBuV5NlBTAQxouAvIQl2t3djta2xyRMLyur9MdK1hsC\nMweZ1AgS25FQgR5RtoxjayBIcfC1VSw+2Cj9iMU14OMsr9yixW9Y8pOQep38\ni9PTAf8bvTB7pLb4TjFUblmUN1FRijW6X9eEM1poWvfCaOTzi6S2iCAuG2yc\npFpw8kGWtShiptyKXhGazdraPNbjRD6hpe+wX+hwuUYsmspDcZZ6QMiOIabJ\nni/m+l5PTiIUWcFQ3CpIFgYr62iq1zpVlDLtuFez8hrxJvviQ/BBLHwuA3iw\nrrn5\r\n=M9iE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCw5d0YkNy2N4SiJwdIL4D9orKuLcLwJWoS3sSc3z3kpAIhAKdLmBGumd0XxQwNyZqQ7bjKpK/2Pyt6ErpI9Dd74TgN"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.10_1589539836477_0.9218811735301751"},"_hasShrinkwrap":false},"9.7.11":{"name":"micro-kit-atlas","version":"9.7.11","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/body-parser":"^1.17.1","@types/chai":"^4.2.8","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.1","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.14.6","@types/js-yaml":"^3.12.2","@types/knex":"^0.16.1","@types/lodash":"^4.14.144","@types/mocha":"^7.0.1","@types/node":"^13.7.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.5.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"4.28.6","@types/serialize-error":"^4.0.1","@types/sinon":"^7.5.1","@types/sinon-chai":"^3.2.3","@types/supertest":"^2.0.8","@types/umzug":"^2.2.2","@types/uuid":"^3.4.7","@types/validator":"10.11.3","babel-cli":"^6.24.1","babel-core":"^6.25.0","babel-plugin-istanbul":"^6.0.0","babel-preset-es2015":"^6.24.1","chai":"^4.1.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.0","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.0.1","nyc":"^15.0.0","proxyquire":"^2.1.3","rimraf":"^3.0.1","sinon":"^8.1.1","sinon-chai":"^3.4.0","source-map-support":"^0.5.16","standard":"^14.3.1","supertest":"^4.0.2","ts-node":"^8.6.2","tslint":"^6.0.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^9.0.0","typescript":"^3.7.5","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.611.0","bluebird":"^3.7.1","body-parser":"^1.19.0","class-transformer":"^0.2.3","class-validator":"^0.11.0","class-validator-jsonschema":"^1.3.0","cls-hooked":"^4.2.2","dd-trace":"^0.17.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.6.0","express":"^4.17.1","hot-shots":"^5.9.2","http-aws-es":"^6.0.0","ioredis":"^4.14.1","js-yaml":"^3.13.1","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","multer":"^1.4.2","mysql":"^2.18.1","mysql2":"^2.1.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.0","request":"^2.88.0","request-promise-native":"^1.0.7","routing-controllers":"^0.8.0","routing-controllers-openapi":"^1.7.0","sequelize":"^4.44.2","serialize-error":"^4.1.0","umzug":"^2.0.1","uuid":"^3.4.0","winston":"^3.2.1"},"gitHead":"0ab2b19aee1cec99f7acb3a53ae993f0fc5a24e6","_id":"micro-kit-atlas@9.7.11","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"dist":{"integrity":"sha512-GxBPpLn7fyr5KgQGLqqmWu8JHd+nUpYwZ+W4r6R+Ok/TQmCC9+0ZhQoRq8Z77vZp5R/silGUrSJ2WQ+k6jcxbw==","shasum":"6f4807ee56f66bb63f13c71ee0e99b44ed144cf2","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.11.tgz","fileCount":124,"unpackedSize":360610,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJew5VNCRA9TVsSAnZWagAApSAQAIVVKYm7nryUZnxrH/MS\nEOmveZ2F5WxQynbOFHRuKzeRjBP6r5gI3pRgCKMuTa6azIa1+RmYvjibllEu\nWDnPs2srgyToZe8qKCzc5jYTGaIKE0+rBjj4cNXYQmePRbkEEriID+vQAuKp\nGr+q1ShrBaUm2EjAI78L+HSpbogqdo/d0fLfF9OecnFJQrAl/0uR2a8j2tgX\nH/ZaGLvVI7DFSs+1SbdmnKH+jOIYkyOYaJGgd6NBVirOMt9436zgFBBvubTs\nVuzRdM20M8cyRJVN3Sy9K7/QzxXEJsHx+OPgXJctZ/GRL1xlaAXuYZo+e7Ma\n4BLOmXBhmZZmfPAFGjODjnvd5akXBEdGY5r4iSsx9F318Vg5mQUjCOLu4XFx\nLyIN5N/jApvefsGkZz54mI6l1NjvblGUx44XLTA2BDSrLII98+duG69OJqZg\nFvsczh/3ViE1oUWpgDlp5JR/Z0sHiUOpXSOKia3HmjwUrZTHC++PmUyi6wj/\n6ltad45aYD5v9jbpzqPDm+ueZDeN7KFN1DWw6hjxGAYauYc+RAlyBTHNX999\nU+3uPQWkJL5sSPNaXIqxBpvYI3TShVFxCtkXzkxHcYoVMlK0C0/9XUX9bb7l\nLMiHssxezZod6iY1OXjMnS4oDbIEPi8plOK118xnweC/PyZP1E3F5myrNQ7V\ngSwH\r\n=rvk0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFSBXOMX0TcZYRr+6oTCoxa2EnEPI0FOuK67viWhX1G4AiBoGPT74a6D/+j41/naD03HYO5ypMBZ5p0tYY1YqDrNsg=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.11_1589876044325_0.2786323170252656"},"_hasShrinkwrap":false},"9.7.12":{"name":"micro-kit-atlas","version":"9.7.12","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.2","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.152","@types/mocha":"^7.0.2","@types/node":"^12.12.42","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^7.0.4","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.2.0","nyc":"^15.0.1","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.1","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.8.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.683.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.11.1","class-validator-jsonschema":"^1.3.1","cls-hooked":"^4.2.2","dd-trace":"^0.20.3","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.4.2","http-aws-es":"^6.0.0","ioredis":"^4.17.1","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.2.1"},"gitHead":"85361739df4aa7684fd680609d3e53c0918e9f54","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.7.12","_nodeVersion":"12.17.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-eAPMk538Mp2AZoVpSVSa4bMlAELRFtj+2Pe29E6rm6HZkiIEsNkkngpq9F9+0gAXhujIcPiyOnJPrpT0ql6lgA==","shasum":"9d44bbb94e470f786c36171adcb8c47ebf234a5b","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.12.tgz","fileCount":125,"unpackedSize":376839,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe1d6PCRA9TVsSAnZWagAAkeEP/jIPbv9tmVYNUbOWdbsB\nyVRXQDNuODjtsA7E/auYljMRnUulZ4/x15a/a68yxEvuPK68bXbSUz0atAS/\noxScfFzK2R3RRQ2Y8AZP5+3x7Fdkk/z5z23Uc6+uDAyH+v+CK93vMGYMyhX0\nQnl0/3Qawruk/uouGIUAXmkFiX88rzBnRUYkqsArhneJWkfpsV5A3ftdIaci\nQmpExEoGDG6AeG9eE3YvvtQmO5VSaa1+5sQ8JVR/BHR3TteOPA+cIjeKj0ev\nHZTN97bsZ4IppBdyCSlR2maDSn8CXc1wcWgBFbfX33YCFJGYsfWdGERxBQwt\n0GS0k9dcNvd1mtehF9I8dUWAR4gfY+eJSNSpzitV+JlaacIlFPjTgWERtoV2\ndRS1TqZFXRD/Q7SBuMvokz7XUsFY8SX8M5NvuRXgFtWMQdVJ5k7ClQpXjJpZ\nx70CylNIi4wL+SzMJwGVX9kblgiOnHVPvG5ehOmgiRJH3j6lpLpNEtN/3Rkp\n0e6UNKBHzKqnqMsa72SeF3H4WcFY/W1oG79d/2/N1P7A/otdaaak/fCCSJda\n2j3tgjaTphCVxYuzAPw8L30cuj/REk3UGaVe+DTGEuHtSkectEJ7AkGoCU1N\nad/WClgubobudakzD1yXBgUmXictSlfVosYewBUw5BU5r2uMwbr6DEHNCz+C\nkOLc\r\n=LquX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIH2j8ALkYwOEx1REYgPSxXmZDaMi2i/fK98YDfABzgCuAiADvx+2z1HzAaCpJse+YYEMfE8AvOlnZLpvc1BH+/v2hg=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.12_1591074446663_0.09812193807443736"},"_hasShrinkwrap":false},"9.7.13":{"name":"micro-kit-atlas","version":"9.7.13","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.2","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.152","@types/mocha":"^7.0.2","@types/node":"^12.12.42","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^7.0.4","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.2.0","nyc":"^15.0.1","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.1","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.8.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.683.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.11.1","class-validator-jsonschema":"^1.3.1","cls-hooked":"^4.2.2","dd-trace":"^0.20.3","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.4.2","http-aws-es":"^6.0.0","ioredis":"^4.17.1","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.1","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.2.1"},"gitHead":"3dac90c991580d4551086efa9041020fc0fbd26a","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.7.13","_nodeVersion":"12.18.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-CnRTYBdvUKHv3QSeCKt8nQca4EwX9wK7tm7OC642t58OmJc130ycr1eltxjiMxTz++OXNFjEcDcMuv0gocR71g==","shasum":"7feb1fb270211ed7ddb58a6cc380a7324eb8efbd","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.13.tgz","fileCount":125,"unpackedSize":377145,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe4IzYCRA9TVsSAnZWagAAHQ8P/1JBznV1WpVA8ObVjujF\nN7qvurVvxJWt6R9a3WP99z+X3N+/wJIGTj1uI7XwCR81yPho9a6BYVeLgxEl\nF3DBJEZi7jLUTY5Pwrr1soiJZdm+cnQ/qwHbPh52bGv+hFZIZmR13iB9ujNi\nNCHvXCsAE0XJmPspkARlymnhHSuspEp4NQw6iPWIC2ztj9EC1wUKLmkWRz/n\n371Z3HgPhiQJZ5aSzcNVQQdyRwVcrvZvc9wD6aiXSn/PagoNUCbQgif31SBY\nTrMz07qniyAHXqnVLowRtutICdUlMXDHBYUErpdmN9Q/lEE4BnmyIixpUTE0\n4mIetc/BD2/Jbwk9ocMbUQSEWHLWbGldVxg+4adVYJyMFAqg4zLoJ9GmvBLf\neeweL8b7zrNX3xWye/kOTZIuQ1IzkdL5tVwVGFV9fvYpawYynl01v98SeeVm\niz2fZUY6Uxul/+6mbSitlOGccn+utqLxOgBYt/p1/kt1jqYpzXglN6COmKyO\nRJ+8BzB8IHarkT3OR+iWb0X/VozDPxzojlsUrJifsDbCGWa20GtwQwwRLSkj\nSha72Y7xT8N91o6EQSw3qONmNiSAIKF97jYlYju0O/YYPfJ83oxZv40u8oRD\nZAnFhkqc3lmLFhzlg3i4nJwtMlep6FdYF8nsRrHsIPHeUow6hBY7snM7qww4\nbU6F\r\n=+bSw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCAVMFJowIHuFHSbGP9rjaZYOB5Wduvv9vaPp1ZD+AOYgIhAOK02lbfk09wRr9Z4O1UgQblwyrao7O3zNm2Jn6lyD1M"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.13_1591774423763_0.05512097346770228"},"_hasShrinkwrap":false},"9.7.14-alpha-1":{"name":"micro-kit-atlas","version":"9.7.14-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.2","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.152","@types/mocha":"^7.0.2","@types/node":"^12.12.42","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^7.0.4","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.2.0","nyc":"^15.0.1","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.1","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.8.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.683.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.11.1","class-validator-jsonschema":"^1.3.1","cls-hooked":"^4.2.2","dd-trace":"^0.20.3","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.4.2","http-aws-es":"^6.0.0","ioredis":"^4.17.1","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.2-alpha-6","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.2.1"},"gitHead":"33bb5a74097185711d7fe1840c2408a0c6ba7162","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.7.14-alpha-1","_nodeVersion":"12.18.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-LsdbqOq0ry12FYqsd7FwI/lVQ9Zl1IpJd6NZ13Puk/3fq5qbpijuw7Ygh1dt6xYrfAJXPhjwN2CpocgUW9uL0Q==","shasum":"ba4f56b196f0c959df5dcc0825bdecdccc22808d","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.14-alpha-1.tgz","fileCount":125,"unpackedSize":377161,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe4MkICRA9TVsSAnZWagAAut8P/RtctxwWT1XA84lp/QUP\n5nySMUvAvDLQSNPqRPDR7NsgEp+zQ6oMnAIYyL6BeACDBpmEb6IRcm2Lj3fG\nwLD6T509dZfUu9QLIP9v6fHbyl2d2dF+NWKp7Vezshlb3W6mL7ut54VrhPgt\nFxQc6if2ibzTl0Dz4iBJSZ2DOh6HS8bRd8ZWJPxvgz+m5qWPbxogkOXi3Izn\nLPgYuWE46k567hJEeiBL3hbUSRN39i6VroE23sFPUN/iDPqlFAaVY31GU20t\nouvy4NEwi1lb7+5aqQ/3sHtg0Q7UHqIUxcJVLsVisXtzSeKYr6ZwM6uGTtzx\nay7l4z1drIVKT0pHGIwX0AyHILHgd2oMgfTeALDq0c/f+fPar4ad/Zlw3Dhq\nrXT25EO/h26lVqYrf/73V4cG8j2KEqZ3tGukkOnzC/9uYzTkVshRHh8HHBBG\n3Bk6mR1b+z/8+FWzD6Xc/0d83XpwLj/hcWJjrLcJhTdj2UzSNnpI7DtOUSZ+\nKb8DbplgF7971TSau2VtqaPPULRc7HvuM4XRbuk9DQaNShNGMN52v3VWOm9+\nMl/mbSiYMvo/fljznvl5n52M7/KEsjzqwgWvMvEbNmnr9Xnynb+3Rt+JOJog\nZJox9ASKa2610JXnW1qEroAWGXeRkX2+rBUFpkDVLsdNdmzzir+NvB+YS3/e\nBLZH\r\n=o45i\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD0SDcBmbzyv8vEzB3U5x9xQ0mx28TwwuW/q2SN/SJ5eQIgI+yc4meAxjO7SWZDbgIuCw+vFPHd2A2WZEuuBKRSXIg="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.14-alpha-1_1591789831811_0.3688468102446072"},"_hasShrinkwrap":false},"9.7.14-alpha-2":{"name":"micro-kit-atlas","version":"9.7.14-alpha-2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.2","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.152","@types/mocha":"^7.0.2","@types/node":"^12.12.42","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^7.0.4","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.2.0","nyc":"^15.0.1","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.1","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.8.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.683.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.11.1","class-validator-jsonschema":"^1.3.1","cls-hooked":"^4.2.2","dd-trace":"^0.20.3","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.4.2","http-aws-es":"^6.0.0","ioredis":"^4.17.1","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.2","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.2.1"},"gitHead":"7fbe4d7feedc4c6b7aae216a28e6673606af3bb9","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.7.14-alpha-2","_nodeVersion":"12.18.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-sVB86qFQmHY+5aHXW8EGZQw2QYr8uZNVsJurXQ0xF4+rYI58r4eoq+23ldz+kFoeD9DX40vOoar3jUz6OKeMEQ==","shasum":"933252c8bcc7331998699b1e53c59b741b51dc4d","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.14-alpha-2.tgz","fileCount":125,"unpackedSize":377153,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe4eoDCRA9TVsSAnZWagAAFDQQAIL/Bx7kgXqYyKQoa/r0\n580dQE4T6pbjWOlit9MLC5JKyjxZsidWniPT584Ro9UzQLlcKZoFzOQSmXOP\nDTODX/T/vbQndUEQ5kFQR5NogeTOx9/uFRgCEjn0YaFvT6v0MKEG19Vz5bua\nMutS48k4iyPJT1TDe0tObofksNV4BHmpJPdcuik24n4nylPAxZysytadE15n\npCOZ7WBEAWpjdY2Cn7vBWyQ0rtcI8awepVMPmJhCFPtZT9aiVDuZ4pN7Vytg\nnGU7ner3RhvI6psltJONWT1gWfTc5LXYZnbykOuSWsIZ08e266enKwQy1mIF\n0uz8R52VOhmcNRzwBujjCLM0AATi/S7pbRhhhyUapeZ5I0VeCdJaSvx2HgHe\nqZfKDkjg8DLizdAkJ5hSuTaQMunTxGtHYHGGkskKxciqx4FVgzG2NekPHycw\n7MDgwd4msmcJzENt6SLQJivV7xlWJnUmC9XCfItG5ZO5UjdFSvE+igBgbhUj\npuKkO1jhcg999sdQC7u7Mo7SjyPUnI59MAm1fedG+uWz5olesoaHM6VnRbAY\nCK+5dC86Gz1qjhoZMAjrPiS38RjiDjY+yYA5QxJagdQOU/sRRrdJzKN2KlXt\nETJ4/4T/Skkla/GOPJQjecmZK1v8NhDXgVN38BdxwV3E/bz7FF3SFLACyW3v\nQFOE\r\n=wiBX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDb06ZPt23T8yPYM0lTccPoOVSe8KLKDLNEDawVWw+MNQIhALUr1TjK4SsBKQ3yTjm1LG1tBjWXY6/vO4QK6n7x5TKd"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.14-alpha-2_1591863803984_0.3627643153451727"},"_hasShrinkwrap":false},"9.7.14-alpha-3":{"name":"micro-kit-atlas","version":"9.7.14-alpha-3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.2","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.152","@types/mocha":"^7.0.2","@types/node":"^12.12.42","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^7.0.4","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.2.0","nyc":"^15.0.1","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.1","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.8.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.683.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.11.1","class-validator-jsonschema":"^1.3.1","cls-hooked":"^4.2.2","dd-trace":"^0.20.3","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.4.2","http-aws-es":"^6.0.0","ioredis":"^4.17.1","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.3","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.2.1"},"gitHead":"7c818bcbe00e1ba9791dafa4ee9924f5bac8a38a","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.7.14-alpha-3","_nodeVersion":"12.18.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-QPBbk+Nq/TR8cKztwatTIRTXVWkgc4hztblPk+b6qHzq6zZYoDx8X4xifKo7cx6+GsI5kNkoJjMoMNYTVNb0aw==","shasum":"10b8e8d95a74cb338a634cd87bd5e69269070e82","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.14-alpha-3.tgz","fileCount":125,"unpackedSize":377153,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe4jD+CRA9TVsSAnZWagAAPe0QAI8HDzUVTjphrP9EnJe3\nIvgayRhQWttmPY1XjgJDfS20jkq8T59b9j9/1fZ6pIItmqSMX/mcIFBTskaQ\nUZjX/XNdlp/N7BXaFgb/usp9hgLiI66Jkafyx3SuGIV4tEljVXuyYWYzRbSv\ntp8YF6iVmkLYFUdyHDyb+1ljavVhyQyURZmOmz/8NpuNPnsJIZmW3XXYS8Vb\na1WOJ/QZNWK+6qCXwMVcjgNWagw1XUGbaKi0gV4E4HoJY3nhQf+gfhH8A0n1\nCDLbBhhJAgQ42mFAd/KvPCV2e7l48LC1VxaETKHKMKFHkT8ItAMMAR1Jy/7K\nc5jnB3y20GZbNp59HcWU/McB/b2ygbr+fr4t49HFwaA9gD4U1/SDIsStiLg5\nFJaSTRcf6wXfZ1tjtX21GWu374NmbqRiCKaOBn6eLWpTH4THil2G5NpNhqOu\nMnAvwJdvB/l7VXu5LrP/5AwEDe3IQ+LApU60H3ruf+ZL7yG3niHCIehim1sJ\ndFem7QCvFCvwsRO/DSBbYddsNyO+EILEb9n2GaVdlz5et6cmSZPtVA9VHQJD\nvRyuu49v/FUUijW8KurAmn4TlZAD9UxdpxZrdAzZ71r/3pO1Biy7XZ0P+9Zt\ne8XK9IAN+F3WpInfEhg9nX0rflRHkhNQM4FB1kdwZE2P8spK5JM+0jF6c7Uh\nNizP\r\n=vYqU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG2AFvtkKBuYMo6YGvK9pG+NvVXU4SuFm8cjwDpbLAQvAiA5d4VNM4yPzlcD14ptt9CT4sZJ/VvrPAH812NV1OOKxg=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.14-alpha-3_1591881982040_0.5762633610252039"},"_hasShrinkwrap":false},"9.7.14-alpha-4":{"name":"micro-kit-atlas","version":"9.7.14-alpha-4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.2","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.152","@types/mocha":"^7.0.2","@types/node":"^12.12.42","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^7.0.4","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.2.0","nyc":"^15.0.1","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.1","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.8.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.683.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.11.1","class-validator-jsonschema":"^1.3.1","cls-hooked":"^4.2.2","dd-trace":"^0.20.3","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.4.2","http-aws-es":"^6.0.0","ioredis":"^4.17.1","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.4","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.2.1"},"gitHead":"cd4c799c2ac3711e2b742c6cf3e967fe2487cac3","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.7.14-alpha-4","_nodeVersion":"12.18.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-Gw8KbiiTQybjrbuPmRfGQkuH0y0Dp7IUtkJaCzCZfY8XDxwTJBQh5jHxupp+ooST2CHX6OkL8ZWT8mthq6+51Q==","shasum":"5a6cd65e7b79fff9a515b646a4a3c3d2b113021f","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.14-alpha-4.tgz","fileCount":125,"unpackedSize":377153,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe4jx3CRA9TVsSAnZWagAArzQP/iVDxfuBCKU+Y+3hWn2I\ncdfaB2X7/VeGfn/zbuNG4JYVr3yfev3JWgxIT5wzuvvtagoX/XuHjEzGNbE5\nbWfijLmNSc3O43yfCIn/S8SuHUU5qE3xcmsHdm30eOlL2NFNMc+jJNo7vqnY\n676uutwZerarGeksGGZbYkv5dJP8u/28w6gylZgVayJl187vZYAUUzXwMCjD\nFM6G81BvoDm1h2IhlRKuqd8Bl4UaamRmcaZowVQssUWtTjixDeZbQxOo2Ju/\ngUppCAwWe3uOrbnxOGlUEEXGq/4LbYtAepSAXIDOarKGLXgKDuKBZaWkxAwC\nUaXHLhTWstoqFfkSeY8uCT/S07dwxVvvOpCElEnZbaXm8FbuSrW+VmLqnYr7\ntpnStg5ATvsvybeiAQkqamDVwSp5/Bg3DAv8oPzpGWXdZpkvp894fJb3eZSe\nxeVT54oyYia5EdG0QR9/9jMCb4py2uhbDHytJ09cjczou7LxD2ci7oKW1Lj7\nui87LAkJDTEkxEcN2k5MrJ7MtbA/dh8HhCs6CUeTX7fpTu0YtSzdE215Hte6\n+UaXYFQMkCtq7MgB4paqtjJTAbz1Pa0KhYTyaMMabhpzCFGsAf8cScKD909y\nALW+teb5Pmgf71cwI5z/mDdqGJUnCQPlG1cINEDbg5tIRy6VYKGd5DnolM7U\nQlCT\r\n=wg07\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEMCICziMvkLVrEyPgF8QQj+3Tzn3T/K2UA7iqXAvTY/nbPSAh9hZ4VHoVowDedoQURuVirwJS7aE9CTRXKAOP49JnTV"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.14-alpha-4_1591884918943_0.23967008581868465"},"_hasShrinkwrap":false},"9.7.14-alpha-5":{"name":"micro-kit-atlas","version":"9.7.14-alpha-5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.2","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.152","@types/mocha":"^7.0.2","@types/node":"^12.12.42","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^7.0.4","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.2.0","nyc":"^15.0.1","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.1","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.8.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.683.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.11.1","class-validator-jsonschema":"^1.3.1","cls-hooked":"^4.2.2","dd-trace":"^0.20.3","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.4.2","http-aws-es":"^6.0.0","ioredis":"^4.17.1","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.2.1"},"gitHead":"6cc498c11f1893e490ee55480e26c86ef7c163a3","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.7.14-alpha-5","_nodeVersion":"12.18.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-eB1RX2c1DM09P+2UwLL/z2twr7MmIsfhu+SZ3SKzkVlWylda67q30KOut0dHlJ0BB2gKeLwVIjTWaaggAwlxGA==","shasum":"ebc47ed125af2c286f3e1433cf22507ee8e8879d","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.14-alpha-5.tgz","fileCount":125,"unpackedSize":377153,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe52tRCRA9TVsSAnZWagAASJIQAKJnCHY0VIDr62bFcphP\n6qefz18FeHZg17xlOks/bTVvK7HKPv8T3ukCPzrXzfYq7SzpVQrZjGaqYqCc\nWq6p09v6ZqKlxU/oJazkXWFvZCzyB1WeEA38i6Z0LmQLFycHgZSFyts4TYXH\nYKDVUJ+Jxt4dOsqiLW8Jn+jrsX8LguqGrGImGWtbV+NWo2LLp386o4+bj2wi\n6s1JAFrBUsGViJbC2bQ/NwcXuBXhrISBxb1hhz3jbW7qmQe0qfUiuzBpbHog\ngW4OU6v1TJtTY/gMDgrZ3+vVpyaOoUKyaRyUVYBZ790lCFvJXNZ2t6t6RvUW\nuqZtGqt7QmcuvhBfSBhl2fbkOSeuQderuDjg03BWhbtnPw0eHX6hGCH+AVY3\nbhhWd1G1I0uX88UGhlfwGioiH2PE6PpkPVYsWaL/SeIoNJzF8OUau9TiJ2F4\nuxXfprmYTXKhd2o+uWGmYXodpIcFSJ+2o/H88DCNK9jjkKdWF+JbYFKm8Z0Z\nWsrdQhPucQZs7JqXsiB2nBNbAI9gVBzJ9sP5dsUU6tF4Tbp6XG/xJzvBwl1X\nwO/U0a90EJsgTz4twf9mQ1KWlu9YrfAHcxesLMRQ8cxcUYEd83wbERfHBsuk\nK4SBI5k7ga4EKvwJ4r2Ul8s4dOIDILwtjVxlLCCvF0i/edYf0Yvvc9UhAugI\nra8h\r\n=lGZq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC4j/6s6z+ZFPWPpCqm24xZPOKJAgcZ4b337mwLxmfJPwIhAJmUv4u+OdEN+hnfXZiKgRelfzItxFzBoAbBoBmldhz8"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.14-alpha-5_1592224592959_0.04037219998639907"},"_hasShrinkwrap":false},"9.7.14-alpha-6":{"name":"micro-kit-atlas","version":"9.7.14-alpha-6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.2","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.152","@types/mocha":"^7.0.2","@types/node":"^12.12.42","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^7.0.4","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.2.0","nyc":"^15.0.1","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.1","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.8.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.683.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.11.1","class-validator-jsonschema":"^1.3.1","cls-hooked":"^4.2.2","dd-trace":"^0.20.3","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.4.2","http-aws-es":"^6.0.0","ioredis":"^4.17.1","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.2.1"},"gitHead":"2150fe94eb89da94bcdfbeb3783714549ac9ce18","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.7.14-alpha-6","_nodeVersion":"12.18.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-HausI+AQjsQqy3296iiX1gOs8r/6GE+UzR2PxaV9SqF9Lww9VtW//Ps/E+QbQWPBXfuHtT4kW8l0awEZryBxWA==","shasum":"2e86b74fb9b656c2c91e4392bcfcf52f9032547e","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.14-alpha-6.tgz","fileCount":125,"unpackedSize":377240,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe54SACRA9TVsSAnZWagAAOGkP/0+q+/LDr66W7k7xr8rN\nUYqFiYiabcm0XCOZJrcEFsp6+ShWRyj5sEX/ZsY3v++zCmqiAMLbUPchegJa\nf4OjvEF4itX8Y7kvrHB/SwbmCkJbeuM7ocKek+t6YyfxWZ43DonIglFtLt6l\nqhtLTBbk/K3HPD6Ctmy+2cqoSCf7BlfWEJGd+4/YEBbh3eDLAU5EMJoFzzgr\nHnpPNwVYECBT+WFQRY9p1mX4cZaoVFuMWhElIGyU3HWorEwQpGq20SH/dsfu\nd8JY7InqVO56SDuNVJIlFt3cP5N7wkSu40HQTr79ONcJD9CgEe5ETQEnCG3h\nqdJ8Yp6SvOHnri9C3E/L9+0xJ4tXxBMI/cUY5i5DV+K1Wn+zOXik+7W2n/LJ\nQXvVQ+GoSM9LzOsyRyAL3jP5H/+mlSB9nnmgbVeY0KitvTAYIDDp1Pn/+ZKg\n2idvkNtuA2Qj5eb/6Ccu/eJ1iFdyQoTpF0W0SP322h48jZgbyCvFwvQ342IG\nPDJvvQfrXFQN1PMUhdaCh/ZOD+RO9mKhpVvNbDJrgAdD0BuxlBaVIlZjjGT7\nSRB7/RI/mdZppIDTXXA4bf+1aEx881Meyz9/CBxzDp9X9I58Ayp0WU8/33NN\nQKesl1QcsF/unxvwH6mPAKVg1AFCCXbI9nw1yrxtyvhdA6VVmo7f+j9YQEfo\ne1ta\r\n=fyfA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGtiN58fkQAYEbTN6/6AqXJWT6ytKQJy/fmaAu9BQd54AiEAvTix21y0aJpWfFqLz8jyRn+FAL2zVAUb0jSuHf+nPBs="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.14-alpha-6_1592231040067_0.6872473022245129"},"_hasShrinkwrap":false},"9.7.14":{"name":"micro-kit-atlas","version":"9.7.14","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.2","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.152","@types/mocha":"^7.0.2","@types/node":"^12.12.42","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^7.0.4","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.2.0","nyc":"^15.0.1","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.1","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.8.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.683.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.11.1","class-validator-jsonschema":"^1.3.1","cls-hooked":"^4.2.2","dd-trace":"^0.20.3","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.4.2","http-aws-es":"^6.0.0","ioredis":"^4.17.1","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.2.1"},"gitHead":"71d5f1c93e7bb8da15adad5b262cbb74f56eef9d","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.7.14","_nodeVersion":"12.18.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-zjmXIEa3o30ombzM5bqJJeEyXCV4roblw/of7/vVoH0ciFgabCiLU7Nu7+j6slhfveKXNZgPCsDBiD4CyrR8qg==","shasum":"3385a4d48e526fa7b02fbde5200b2d31ed54ac65","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.14.tgz","fileCount":125,"unpackedSize":377232,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe6IoeCRA9TVsSAnZWagAA96QQAIdxr5C7JorMIGCYMu8A\n34/DW9UjAJw7yBOHc83jGsxnS2fJmT8fQLBxao0GA5kYn9yFaWkz+1l5JaW1\nPVy3Zv0M1cyKSkuqYgnACzkkTLfB83KUwoCzSidTBgHRFW1kVcmgzbvBSrhh\nlP3By4SdwIaSz/vmQTrkz23zMCpoZTIlYPIhhF+cNpE+Z7IjZB7Xi/2pcZ0n\nXn2S00pcPzoEpEIxnNr8Eifl93pTthcw1oNam4cZeZtA//OhI+tvTQt7RcJN\n83ODKkjjbQyR1NuRS/GjukRB7VjZDt9fsaDJVipIH93yIMVr+OjS843w5DN2\nswlWw9oT1Vmndix0n6Bk7dGRO8Yy3DffO/Xr68kE91eESinr+vwA6yf9SfAK\nfS0afH2zcy7OpTyLDAZ9Jfr0QE1f7ewD1lrTkwPIB/BAN/UJ1U2SPqZqLr+X\n+jtkietRst88jqr0SkjqPmyS+cvuSyq0pwAXXT2S2ImJwis4GviNpwxl8B5e\nClK1EmVmuQmxSKH2r0G8mFtjfXBLGMnfCGRXJBS1G5Gd2TLgi5fiaxYL9wEp\nbMsgIGPzqbAwSSXdg2Meqz7VSpCq9UQkRjICnDhzttLxH2KdQRjD73XvNNUE\nl+owYGa8AZegMkJ7cTE6rwymwQGeygUp25Bpg72kz+b76S+VxIyS+oFLeG8e\nmS58\r\n=EhCb\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHqi0NOniNm+/vrpp0IN+HYzSRlHCB7XstT5/7VG0CjoAiEA55GLBrz/Wk+5f72lWSbzxvYboFnLFgq+Tnyy+aUojTU="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.14_1592298013899_0.06994048501293837"},"_hasShrinkwrap":false},"9.7.15-alpha-1":{"name":"micro-kit-atlas","version":"9.7.15-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.2","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.152","@types/mocha":"^7.0.2","@types/node":"^12.12.42","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^7.0.4","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.2.0","nyc":"^15.0.1","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.1","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.8.3","typescript-eslint-parser":"^22.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.683.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.11.1","class-validator-jsonschema":"^1.3.1","cls-hooked":"^4.2.2","dd-trace":"^0.20.3","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.4.2","http-aws-es":"^6.0.0","ioredis":"^4.17.1","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.2.1"},"gitHead":"45f61779db86df4f23a9508144dbb12656bcc4f0","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.7.15-alpha-1","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-DAmMyjTWksaA+yTFfw8wP/pIwagZDls9MTlQThp+LeV7i0SdkRKL2XXDj+l92Bd0xelnjng5JU2odmcuo8JhYA==","shasum":"1b4a250dff59dfbb81791f2e257bdc3d0280e412","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.15-alpha-1.tgz","fileCount":125,"unpackedSize":381208,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe7KzGCRA9TVsSAnZWagAAgCcP/1/ShrJKDLK8jPa3S7pf\nMpIFKGacwUWEBJ/qFpMSL+MopfSeOW0lrDmvM/Bz0vDTfqcNcv95xwrsATiW\n0gFuPhxJRqp6pGRG4bi05q6ahOnn9vivVKfQd7dCp1y0tNvwK0oBkjmIYvXg\n5nysKjDZ0LjU+uwQwrSKcpUF2umVLN73BCiPkU3oNLaTxThrlfBE5rjGuB4/\nD3TLRL4v3EFxb836mqxZ4gKMI0x3NrsnaB7ywjYKbk5wLn//NA7kAPh0ihoJ\nOhH6e6BCszvFnrDcdnY0eE/QXw9nm0M7yFPbVnwb0y9BMOD6ldRRMS9BxULz\nTx0vSBuYxKvs2iRTgG8VlGcuZkPLAqD30ZjY16UccWAOyWf6P+HiRfxZIg1H\nNiVa5qI8wQKELfSfuM57uu6D/bG8jd+U2FJQoGTfkp0Jna9LaVEMY1fqiCRZ\nTEOExHZx7+IZ308sJAf8zTga2V2orZw3Lm7Cs9pJaXmXzVb+sgYdsG03m6Qg\nrefoIlJza6kiXXMC/gW58BEuC5XTLFnhD8GsCw0TF+K8Hs4NnFU7Wmahy9pi\nw94BmloQ9PECJCe5kmcS+ubYRzxu1Af18c5Y0ISDCq2y499abAPsvvHeKbdg\n/h87vCKDNDfm0MOVWBAb1w1NY0+6xSebRdG4iCT9Bikt8h+Q/R6SiwOu5ySN\ndP/a\r\n=Yh7Z\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA0Y8yLNGA+nCwkngUGJl0mQErhKcLgBMPl5GDMgImd6AiEAxTF4dOcSv9Xm2zx5gs2HKcHyFPCHy4vNO4whKfiEZIQ="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.15-alpha-1_1592569030308_0.3808840241475264"},"_hasShrinkwrap":false},"9.7.15-alpha-2":{"name":"micro-kit-atlas","version":"9.7.15-alpha-2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.2","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.152","@types/mocha":"^7.0.2","@types/node":"^12.12.42","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^7.0.4","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^7.2.0","nyc":"^15.0.1","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.1","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.8.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.683.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.11.1","class-validator-jsonschema":"^1.3.1","cls-hooked":"^4.2.2","dd-trace":"^0.20.3","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.4.2","http-aws-es":"^6.0.0","ioredis":"^4.17.1","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.2.1"},"gitHead":"ae8878a9b6302c0c41cef737464b980691571150","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.7.15-alpha-2","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-dNF+E0pVDyigZ7HPU4l+ZsNxNra5+lpTOvf9/ppLB+vNQT5Ani8WYBzSWC4OqiFWgmeAxNQAN/6Fk7aZlp3V8Q==","shasum":"b9cac73380aca0c528addd0af1b7d9000fcbdf05","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.7.15-alpha-2.tgz","fileCount":127,"unpackedSize":381968,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe8JlmCRA9TVsSAnZWagAAEtcQAJ7nsUOsSNTsu4zo51dc\nItiwIZYmPodyIF9P112L58zllZp+4cMPnzxz8SdTdz43vUKdNdRYbIsQc/UD\nc4efAPk2jhc7j9xRG6Nm+QNfJnyhRjIPTqWxd36rWjOaSC1u4NRmg9+8l2tW\nRH1iipIj063yMn57Itc0GnzejlAKbd9VC+VNeWxbJF2UrC74bfdN0+Bo2Qql\n8EsuzzoO/tuyCg/BxtXfm7/mYxbqwmZcSstwYhgOo4fvxnuRMbUKfFgf1t+D\nbwY553SuT9vNiqZE3JJcZcaT4k6N64yvOfWR8raMTqvZlBBGC/49yKuQwIH5\nuNjweJwac2/YaNGQzXodUmtw3+rlUMKcGcHLN68k0n7Sx+sf+IJ8A6a3d1V2\nbnO9ryhU2yHFM3qySUJ42ssj1EPNAPoYdY+bRfHAUmhAnCCzluA7aXdLjeCk\nwcpL/HLJeATyEahZrBxYqsZXbTDEzPhoeo4tECWzDOxZviUVK9gWzh4E7KOq\nJnIKTimfkumxriz6qmDIDQODutQanAbPwIVaV3mbruCt2aMr01shlM5TsA1n\n0YWC0/Ta6MRIo+zFLlxx9+3JGmPT9b2yZH9JPxGSn9woDUclDH3joqa5/mta\nT3Zc5PoHIfq/ujb1/PsURqmf4lvkUTzfl4azh0Knh5aS26q+BWVnrkw1oYju\nw5DW\r\n=Y02q\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIE19gU3ggrExoRTXo3/ZR9DkN4Tez7/VaZRrzgBLaQBkAiAdtQJiC5/cCWn7gY/OutEDEJrYW50v9CtOWmX6ctm+1Q=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.7.15-alpha-2_1592826213657_0.3287047766149509"},"_hasShrinkwrap":false},"9.8.0-alpha-1":{"name":"micro-kit-atlas","version":"9.8.0-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.156","@types/mocha":"^7.0.2","@types/node":"^14.0.13","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.0.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.702.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"^0.22.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.6.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"8f4d03c26b65d3e3ca5a90ce02657514266332ee","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID() uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID() user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.0-alpha-1","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-Ggry6mOIbhR5E2cRWnw0sXuS8v+N69jAsVId4JPjMTONRmPWEHFslNH4tXWUKn4b1npCgq8StPgMH/9Es6s2ig==","shasum":"93897a168c2a8a5a69e39bbb11083d118356d862","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.0-alpha-1.tgz","fileCount":130,"unpackedSize":405850,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe8wSSCRA9TVsSAnZWagAAE2MQAJA4Nrg817B7V3yx10dB\n/0M0xwE7ZsWFKKTOF4WvxW2HaMZzB4Q1T6xfrt7a63JjS0UpdSL0LmURc3gh\naHPONhez3m9SqPXxc8aPr/h1h5vidh+aVrwUJIgW2+0e8gJdqXtKoFt1KHEg\nYD1uwjsz1vwOHFG077FitcVPsqN+GEyZLPSUdFw36fBSBwMkitUZqP9bFvUX\nc3w53838eC2rSvNy9gVsthTRQV3XbEJ3CMlhHwTA1k4MkgZJ2dBPPC0oIu9B\n3FgzNzTZ88jlWVirucBjyu1x7SAsxTmdcxGTTsfw1vGWz66LiT7JKjSkMUyn\n+CRt5JLS7rZXuH2dua3vIpOUHNieFYZyv/ex4vNQlx3spn+5cIB5EjqtFCRD\nwWH5ir+TsSSAcNh0DXYgZzeklYzbDwWWZ5pQ3Hzy6HubIk6WgQqAKGJsqXNr\n5ZKn2peElvP+1L+Gib8fysmU5OFnyrzaG1dNme43eW7p/MqQPVNOQK3Q9klv\njaFBSq9u2HgHwu0RzeVXy3adn5S0Rj2ngkT6h4bipLNhlXpQv8I6IObgm0zz\ny/hkXaZiGeNKOHNkKrSYyjTzjeYBQzrNXjTcGvyrM/TM36Mt8r+Gb/kCVIsW\nJoGIKh8NNnnsuWN6U8ZoDJ55wdH2SonukjujiP9cnB5TE3dQl0CAL0sH7iqd\nhX0L\r\n=i+sy\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB5so8LUmTnEJLw6htEhD4RM33HX99Qujgz6iBVRSRXvAiBn8PZn081SQg0Be7+JqI/4KEuAISZRB+kX8XkEk8v38g=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.0-alpha-1_1592984707473_0.622433725279929"},"_hasShrinkwrap":false},"9.8.0-alpha-3":{"name":"micro-kit-atlas","version":"9.8.0-alpha-3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.156","@types/mocha":"^7.0.2","@types/node":"^14.0.13","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.0.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.702.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"0.21.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.6.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"68be82700c1b8d000cb14eb1528d58793b340a77","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.0-alpha-3","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-vuIXCWi+oaWG778t8RoPHgcxqnkrB6cCHsRzKWgaLzom8Dsm2L1PYOxu7NHjca9isQyTBi7sR4iNLOmzEc22nA==","shasum":"71dbc84d2eea110df1adffadf26e49624ea6d1b6","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.0-alpha-3.tgz","fileCount":130,"unpackedSize":406857,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe81GPCRA9TVsSAnZWagAAm8kQAIe7ZoxDuVsYG2hLTYSo\nfxdlChlmoYHsje1ksyff4KlyoLTPNzzLEwvQKBZ+N1TRO+qBOvwecoFECRJE\njDjsADMrkMRcMnrckBxZfRnDCjP2n+qAYDCrAnjB2xIxfvDRExdtoeHEGDdC\nt5mA9ReeuLFyrGYsb67qZSuqYJWJcfGcTFmCqLuaZJoM/7xr3lqFa+Z5rMue\nVe1O/KhRLGKdLaTGtYKTsMvq+bxtX5k6fBWdoFdK0Xi4Vi3vf0/RwUuIblXp\n3/l2LwTdo9YOU/NJSXCGXFu6TtmbNIql5dYIM4tgpyEsglJdjEjN9GYdMALj\nu/HqyVhJRTowg0osxMGRgUhvjyWzGizFqM0gMsM2GbVb5N7GX1nwXrpKpjFr\nnB/+RPAokVwjnxHm6HIcxPzVB9zTwTwpfJbSxrJ8Qh2C3xrcJdfTqFswblTv\nWIXrzFEO/nRgDFW0sxMxTKCftxnNergJdngA88bnpMtfVSTdbomNjq0s7WdI\nSSzTgUptela1LJ69efbuodVoM7+GlyOxMDVT7dZg09NqW6zEePqXUupM9QP5\nxbTHM1MsuY2NgvBUMpTTuitbOAcPOuvQjnwdWW/NWN1USxsuLm5K+bLNNlmO\nGnmQqTKbFyuxBkH5qDoFhU8jJ89+GzVhD4L245NZrERWmkjRfHRpvsdJFg6m\nFxck\r\n=SSe1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDuIfpBUNha0NcxPp5gRp16RukIuQmXrvCYNgTV3vu/agIhANMHo0/ts7HGzYdWl7z58UHi1byZnRE6RgTwx/7Fwxcq"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.0-alpha-3_1593004430744_0.33050088670374356"},"_hasShrinkwrap":false},"9.8.0":{"name":"micro-kit-atlas","version":"9.8.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.156","@types/mocha":"^7.0.2","@types/node":"^14.0.13","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.0.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.702.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"0.21.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.6.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"4c6394e51d8e16fcd236b269c69f005cba7efb75","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.0","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-Eru20p7h+cREq1L2S0L5xxXCWZVboLYO1SnPcsRoekfPNMa8O1K6TrpvurnnSWZgz6cYdLn3c6dzT+FFrHJkFA==","shasum":"bf0948ebc33e5917f459e00d8be26316d9b68241","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.0.tgz","fileCount":130,"unpackedSize":406849,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe81oBCRA9TVsSAnZWagAAIIMP/1jSfmGQ/iMjSqeBIgOX\naL0USofGb9p5c9IPJ8gE5rkpftaQrcoKFsfBgS3+8Zo6omXxDX+B4AamwC80\nQ76GcLTWTXP5Z20d7lFjfqxOYB3Vx8Rm5qTfvgPAzskZ3p1c4D3d+0iJ2SK8\n+ARrAq6b6EcAfZm/ZaHgyIy7Q/+U1tdyfU6ldTuIoVY3dRO+tBBKIcJVgWSY\ncuO7a6cNYoycJnJjYhlBJLNqeWGZzdIgjNHlXevz+O1wTF85obh1V2ST3wsr\n7T3ro1w2rCQWa6i1wCCyao0VSMuaxGG1KY1Oh+COYXuyrHrdMKqkTAs/zXbB\nhG0h5p71bS+d3df6jEZwoPKeuRyCgfLzMW/4lVThn87xw1RiXkJ80SN7Aas8\nmXr7TSL+LkQTwhDr4mPPM0y+r/MhlqvwX6HDhFIWsdTC6Y6EfKSVvEuQ7YqQ\nM3Wxe9SLxKAsVeGbciwv2ln0rc3dpCNJnAxA4Op+deKBezRPhKj7PC1kYBBB\nN4RlhUmaqKJCD4W8DyxIVOuCeR1R8G69UPKqOF+ZQH+3S8YOTOdOD7Bxc8Kp\ns9qmB7ZVaMXT7p/UQVEtu/w/wA2txhfF1qgPjuoOgPzPnaiNvqXyXgwGdKME\nn3lohh8x5K+A+AiH5cxYjYy5fCeAgYpUpQYGOC6GqsvErn9MI2rxLjodsBao\nRaGO\r\n=N3gf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE5oCu22VSozoYbHPBzPJxvId0fYxW2mZATYzsJ1/R+EAiEApMPLVRLmIgn4AUCvcDwdH0IAKVkNoUsZVqPFEroK/qw="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.0_1593006592739_0.7263218760524015"},"_hasShrinkwrap":false},"9.8.1":{"name":"micro-kit-atlas","version":"9.8.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.156","@types/mocha":"^7.0.2","@types/node":"^14.0.13","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.0.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.702.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"0.21.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.6.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"007845ac6dbc4ad4004c9f9c6050fd4772536946","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.1","_nodeVersion":"12.18.2","_npmVersion":"6.14.5","dist":{"integrity":"sha512-bw4pzyJZzsUSYxqFn1jOUrEXLsXcbj4/rDX0Pn8k2rEN7PYJR5fzMpda8/qsIWT1pLcgbbdEeW7ap4eNw1B6Dg==","shasum":"921a16c4523272f63648d266fa5457d9eabd597d","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.1.tgz","fileCount":130,"unpackedSize":407002,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfDqhrCRA9TVsSAnZWagAA5asP/00ppMvemIhipX8JTAxL\nKAdEKT0abbTUUT2jbB1/eBoI20BfBz3tR8dEgqyy4cpW2WSyTo3x6OT7TRPg\nfCJk8YwPWMeZC2Ognz6ms60UZnHbmG9orQ3W6O8ClD69AP+i4q+jXV9BuFKC\n7y2kVW6tEVwrOawkpuvIYDR/RvWp8SnnxkhjbP72gFrtJSdRcAIZwXM8PfRC\ny1PmX+u/hgTq+2v0j8XbdpaXCwj1Ka5qwMNEXnLQCoWIocK90T1V0Xs68N0P\nyGcHBuu6jd4c1L4kz3ZmtCBtOwtkWqA7SXQ/ZfBOTJr6YEMPSsJVVIXXulp2\nYsdI56GzvxV7AAoAymFbhHe9EiHR7eW/6wk44dYidaROKlkRETb9CK91Cfuu\nb8LoM7Uc5SdMuYhkZ0X9z6rVZYMrbRNKgSfM5V4p+gTS8X1IUsoDuKmWs3Lr\nG1nfjaKskpaZmhsdk08E8PoBsQZkqCm0aRB31dh1zfVJFH9gvi7fbNzSEfAW\npBUmZYg2/jSHzfv3gi/uWxOVHgxSAwNITg1lVpgqVrDRAKau9tjtthrS/oLc\nvUdWDkdsT+zRc5bwKlNQ1YtiIJHCzR9JhVXfMIiFH8Z4D8gSBb1Sghojp+WX\nI4rLLtfqd6LezAkREpxdETlNQ9W48DxupU2AMjCTQXb8jVi3Yxb19+z9ygck\nSVaj\r\n=qdoi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCWB+b0McrA5psg7en5xmUupoGpfuQ6HO1EydiXY+6hrQIgE10wXhlTnIZPaOIIrC3RM2l7pnBbDDtXqtChKO+L4N4="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.1_1594796139035_0.9092768428186189"},"_hasShrinkwrap":false},"9.8.2-alpha-1":{"name":"micro-kit-atlas","version":"9.8.2-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.156","@types/mocha":"^7.0.2","@types/node":"^14.0.13","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.0.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.702.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"0.21.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.6.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"a2d1e884c2060f5a689cfc6b2c144c7f484a134f","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.2-alpha-1","_nodeVersion":"12.18.2","_npmVersion":"6.14.5","dist":{"integrity":"sha512-tR2VC3uBVDM4Rf44KKS1Wot81gkPZDg8reRV2PxJLHxlmDORIdqfnkCCn+KXDrqNeoTJ7kEQD3THvLj4NIHg5Q==","shasum":"3bcec633ebf8708c81dbc61e745cc38b04706a57","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.2-alpha-1.tgz","fileCount":130,"unpackedSize":409653,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfGA0yCRA9TVsSAnZWagAAX9oP/12mQXfHlfFynFmRAzN0\nGkM/a2vCzqIYHfkNMX2xDRj0lSJSlU7MZuGtAZEV+yFMcf8RWMAZ1PNyiGDA\nNoeitBJ+8MvmDHTOpG0Tz/o4EcuJiUSKbTygl+hhCWxLqKiIgJZg0MP6BfWf\nOp/zssopRgbv2FGcWoijiIjJy870vsTzkqepAsPftX8BEDwdfAcBy2HaEMdq\nGtsC+NYRBcXU/YfnK6F8P2hfSeEJH/ulJJ2dTZdbmJ5QWhALdZ0R463TA65U\nXaGOq5Zz1scAivRsbIaEshGz89AIlI/Uo6hR2k1PrC9nWflpK1HRgUrUzEA/\nmPxLVQ0snCfS8S5p9JfvX/KxjQ3n5SFtpSIR8awPgeK/BBZvsq32qjfrNWkz\ntDbTJ1FhckVKG5YsD9JRBTGEA6bhvvjIW58OuU+oMeUBPX9bW07OUYESpep7\nEAkBpRgIITU1S2IS9AwzwZA57TEIUzQn1fbYNFW7xv5shCd9F+m4ib+xVXWN\nDhnzz0w8MBirfkwqaONN6/VGywgh6kYCcsQXrVHHoMwfGdBHkETTgXvP2dDR\n7jTjOwsQEdbD0juWNo6SUMYCvVv9keauNyO9w/Rrm7mLJBhYrceAH4dVgYN4\nTAS9YXew49m97ktQDNW7dm+A+5xOODT+UYDVFqpL7SCIaDBvcT8W2pD4TYww\nl8N8\r\n=BAXU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDx+JX0s398gVYXzH38zvCCCykt5h/4vB6S0kpqZuANhAIhANWvtEP/K0vFbVnrI4EfYyNi1d+bpCNtkeSA28HyKOhr"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.2-alpha-1_1595411762396_0.5192217258442151"},"_hasShrinkwrap":false},"9.8.2":{"name":"micro-kit-atlas","version":"9.8.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.156","@types/mocha":"^7.0.2","@types/node":"^14.0.13","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.0.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.702.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"0.21.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.6.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"52f7ccbe9b3ce93994d4169173b74c9df7b9f4a2","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.2","_nodeVersion":"12.18.2","_npmVersion":"6.14.5","dist":{"integrity":"sha512-oFvL9ON7DlrbVS+V8xrwLZcb/8JCVhy0fhoyqbdxkrzzpeWy6A45ZqKCBucDBIn/TSFt8DIH49uY+S6EoB6qoA==","shasum":"1d066acd40a19f3de46800103887613f8fe6cb4d","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.2.tgz","fileCount":130,"unpackedSize":409641,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfICrfCRA9TVsSAnZWagAA/kYP/iJvhr1jIEEKC5glNhKc\no+JHdLzyu5uebGwhHwV8+g40L9Lohv86EklVoiMrJ/lECyAgKh939KrCn/Mj\nrnuel3nR2Yia6bnRjGVmwO+EUAkByBZhHGOS2in7EP+TM4SpD0DiMQmpkNva\neKUcyc28Vv/z2OR214jUSGVdO90/lQfA8JyPhwNS6NCxcpPi2iEVYu+DZyDy\nZqeLRsBn9AobbhoZgmNqeYSN50VzkL/4ler0Praki1vD6X4z7duvY2ajDyqX\nF0FTedhf5ZfNi/CCbcv5AtE+UV2HgAP6/HEzbRo6hE/M4I56khv74RhhPLlm\nz3T94XxCsKG1BKlKTFTSRACzMtEyQYMjZwZHXUBX9kjTl+ForRmUD3GMplAK\ngO+JXIGqo/GWk1TA2YLSxlmW4SA95Rz15pcdAWeMMzKSKMold0adLaT4AeeP\noTd0JF/Te0jXgrbaR7Kke4nvVMnu4IC/Q5JVSC5rMJsHOrR2r66RyJofy06X\n1CR/+lzhywK/Xcwx9gAxY3ToKXQcoT1nldJcA7kz5AcHK+D2ZgxNcA9jL34U\nymSScWcnNXG6R5+L7JdJmcO+BdvXT6S6+6O9OhfqFuvnza2s+wFyyzS3tMkG\nKt/5sJBGwXbsKNc6i0kadj9zJ4NX3UlWRo80cS8+jb+wTmYxDc8rDJicq5Rj\nRLg2\r\n=OqDX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIG5ew1xyl78vB4143Do5ALoI+5iVTNPG8SwMUkepOY6DAiEAlD3ZKXHEjCxJtaWSgwNB/3V8GAK64cC/9hfaS55awfk="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.2_1595943646767_0.44525705710530383"},"_hasShrinkwrap":false},"9.8.3-alpha-1":{"name":"micro-kit-atlas","version":"9.8.3-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.156","@types/mocha":"^7.0.2","@types/node":"^14.0.13","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.0.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.702.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"0.21.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.6.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"78f8725a98905cfbaa8f7ce7b0dd11e82ec604c3","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.3-alpha-1","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-dCytChiHbE1JxXjVjnhazPeoEQq3V1W45sFTOHu456QZkHG1hViqmwXIFtwDPooPYckZ+nmku6GHXg/cK/37xw==","shasum":"e54840af9ae8a4c7c91497664dbe9e5aa1ee6b22","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.3-alpha-1.tgz","fileCount":130,"unpackedSize":410110,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfKrjxCRA9TVsSAnZWagAATWQP/jSzJ8cPtl6Tt29+IvNI\n9hXGMYB5JHjlYBMqwLzUgsxcSpfmqPqUJrd9IlEGMwI9pC1EPN3lSG1u6y4n\nCXUOgapauoQDkkGhCssKwyRKal4cyYfvCLmz0KNyxoeze3BbCUO93MCQr96L\nI6Ufn4EDTZowMVEcLGgLP4iHP0yjhPMTeWCpuCNoUP4am3BT35rH5zqYvMdc\nPquRXhnemYs0uaoHjVDHFLtXUVFzKhRrj7C2zpdV6HkU4HKGPhVM4DHDynOa\nrUwyueRZlnNhF02BshILySSPESEa0ZJN+RZc2jkDadJvrY4yQliTW8rw1GzZ\nm23PFtMgbyr0pz/YhkwVQ9iSiEEwPMc+B3hcNIKfSNswJUh3trV8lrywMvKn\nCqMRcFpyUMmdJZZyKESY6YZUYvEoIrj5yHT3rSQ2MX0zJoIm6IB2hehhayZQ\nLBkRYgNSPpCS3inY77QeG/HMiO9FbiNxBdghRCwjU1hib/ps9jz7VTlHb2AS\nlx7859CoA05G7ZZFSOx6ZWKj7jWBQAFi5OkUmuCd16N0di95IutJidFi1hW/\nrmtba4IxVu2vcNJQm5QA9gIGB4jA3m0xlUOENvY+YUcHvYHY1TQn+9mN/dki\nHhCEMWfyF5r+dMudo+kQUR5G/+EbTGxPnG4RLwbl2TlnZbUEn5ZRnOagFDwq\nnu01\r\n=leo7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFDF1Yl/NnAGM1hFfB1H1CaMTsB5megamyFaY/TKrNb+AiBB4L2cKNLEfzNlsn1awUZyKIMIOkl1exn7HKO38bpx+g=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.3-alpha-1_1596635376432_0.6967695192395735"},"_hasShrinkwrap":false},"9.8.3-alpha-2":{"name":"micro-kit-atlas","version":"9.8.3-alpha-2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.156","@types/mocha":"^7.0.2","@types/node":"^14.0.13","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.0.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.702.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"0.21.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.6.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"72a787b603ecfbb24afec1fdf59f0a7f8b835b64","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.3-alpha-2","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-Le7T8vnHy3p5cnVfgMhfqYgzHjHvRGAjfeTSn6NtPxcTjn/pNHmhfEUGhoqONS6mmG4ZEWQOtW+/PRdvVDsfRA==","shasum":"b034eda7be87027f8cf544941512e512a3d6aa8c","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.3-alpha-2.tgz","fileCount":130,"unpackedSize":410300,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMpbLCRA9TVsSAnZWagAAzGIP/0NCAaViL1RBP962RfXZ\nBBITa5fK0s4+JEOI73k06ENyD3NKfhVSvWieLKfw+o0pR/YGsBxUlrZPwotg\nSMQ9ju9L+q1NKzxmMumatzeFRaxHU+YEE58jnPZdKMK4VQI7BcKss9n7+eNp\nqCq/bNDpUJQQPqLM7FZXckkZ/4Rekhnhl1BqFalIk/V4DYYsF8/H5vg4+mR9\nfEaOWK+rk8lsHbloiz8euoCrY8+5TxdtKEkRQ3qofMaHfILvkAgvUlL8XDyj\nO18yG+aw+zl4W8T5cA95ArnPux57zF/Obahyst/H17TMI17J9LQL2JUUgNl/\ncKbJzYE0wIXDPLvRYIjtao4VwFrMac/IG5VCNta5uF/WjG+5Nm5LiRQfeirA\nphqyOUSu2k6C5pl54WgBMKjhUtAaXylKzJKLXPDOTRVO/4VZHtqiCO+I3Bd6\nG5wOgYJG7xel+mVFmX0yQWOHtCiM8G4HYnhPIOKLTrNKUzm6coR0+vF5JFV8\nGje3+ci8QIKySTwK/f5Gzyx7RepDEAX7bLjMlCVqSzBZS8cRAjYFkkttDWlL\n+Fnnt9Rq2AXHQiDiK7+/0wBrC9IITJrhx+WZSETfFsZ29e9NJ/LtyeTpdAdE\nC5FY9m5SeQCt/yll69aTguH6aJkqQW4vokUHRFdPG6ayV14ynDCFUGG6Qhhb\nN2K5\r\n=A8HD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCN2wUzNunBcDFEsCnrAnWuT+uEvUNC5a5j6RVDfSNEkAIhAJBL2knJXAXe7VdlIzqkCVxmpDdZfF5Tnb3vOTprX32e"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.3-alpha-2_1597150922714_0.4999936943192482"},"_hasShrinkwrap":false},"9.8.3-alpha-3":{"name":"micro-kit-atlas","version":"9.8.3-alpha-3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.156","@types/mocha":"^7.0.2","@types/node":"^14.0.13","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.0.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.702.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"0.21.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.6.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"01f1f722449dad83010e17d21fbc8dbbd561558e","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.3-alpha-3","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-IcbSkNzcPvUG9OK7wzOgCmIAsBzaTlVAbyweiytYFHgtWSxXo2c0wGDhvqfFi3uVmCRCUZc/8KvXuDU7/HV/JA==","shasum":"99b14a10d5fb52b64e5ed94a22c04716d4549093","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.3-alpha-3.tgz","fileCount":130,"unpackedSize":410973,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfM7ifCRA9TVsSAnZWagAAaIUP/18EYKVmmff2y0NLtvH1\nqZujRpBnupRfgKCq/t78gJIs7eZeJnnK+C2QVsOnDTXQ1owt+dFkk/+K0eGM\nqdBHRuqo51BcxCoEGu8kugtK9fJyDxTXAT2K7r1uFrAIkdAamMU4e6Mu7SaT\nMX19oBdBouSFXJ4Ox0G120zHEcKbgdIqkSco/XohA3j01/kcvVYdm9PHFeAA\nsVB3DO6fP/oRkZqXgzWx6YMg6MGN6li2okVwNx9k4g1JhKLUTJRbpyZHhoFz\n/LZaEOFRTqqZxYarS32aTTRs40VQ8vZ8RIEqnZzLutGibHKzA77mcXJXJ1nw\nBil1kqDnQEo2nZvoFQm0rOugqMNXMN+LMlY4xR+Y2PpXIwPWYP76E58iQfpM\n++E0Zlw8sobvzYO21L6iIl1ernkwhqGcwSq0df6dVXR0EUgiR3wiOAUkRLd9\nMLSu6/r1TSaXFkmkGuDFIIGaP0AElNfcuUKKPDCjoYRH+9NGZXIJRiHKGZ7k\n1QnZjfOJ9cGBCaQc0ofiOUDAmQ+hnOSplJqPV77B7JSTcSwrRxZiQUnNiou1\nAxLduJv0afG6huS/F/wYPWU+4INGUn1lERl+1AMX0CL/pgSRUicZOYZ4La7M\n59HmyKyWlzFh3xEqB696Egjw7UiqwgV88kQ+j9MqLMgyQe4C18F9+tedjSQx\ne/cy\r\n=vV9P\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCIcJmygYM+kGs9ztAXP7UIwcgXMLA/YcvMVkrZjjzYYAIhALnrHR+B0zckWpcyEWbV/kUDBSSGFA9AzhnpqS3ohxXT"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.3-alpha-3_1597225118830_0.9426036114966954"},"_hasShrinkwrap":false},"9.8.3":{"name":"micro-kit-atlas","version":"9.8.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.156","@types/mocha":"^7.0.2","@types/node":"^14.0.13","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.0.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.702.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"0.21.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.6.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"69fbaf61866b3577199be0f961fd696786efabba","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.3","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-1TB0JlVqhUDD2ahSW5xi5oAwiYGv6cVus3rKrXsxy0WPNETzZFBoFzqLCc60KKcvlKdPD9akoRdrcSfYItkqBg==","shasum":"c62c2893baea0ebeed5e9872e5dfc25106bd3a6b","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.3.tgz","fileCount":130,"unpackedSize":410965,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNOJvCRA9TVsSAnZWagAAZmAP+wWBLs6Hdm5/ajbGIqdL\nOMhLkNEwmbOYlgscE8ZsZiMzI9rSX52985In7djfyYexTAyKb7UdRqVpc68x\nySoc43wbqd/zgG3HGXWx3BNSXLUnkkO4eWpXM+ovrnc1EF8oeadWWggN04Fa\nOsnToqv7xv60AwMRizc+xoeBblqyN4m5VWq81Fy8P7zMx4Gx1Y8nsQ4VCa8w\ndQW8fe6wcGx3/pfEwXYCK1ZLbBrvSVagPFvRH634C9b1Xu5wfirmdejV2JwR\ncaOx2OzfQrwxkuIhsCw3+Vt0Xu3Nfu7zLDAdvU6WjyPyTkdoS+u2PB3lRVml\n7Vs9aOpyG5KcNfh/N8ujja/hNselZGGSO/QNLSrjbv13x5MXmEqN422gTlw9\nbrGCQHllIyWu4BfiD97n5jD2XlxQmIcG3oRPoOOEELkqAuNLhr/lYsH3h6ut\npha0TKxOkNaEwehD3KSjuKO8V3jfo9/zs8ounPXLNQFZkb6O67YI1DAcHJM3\nhgqleVIksiYG+Xjx3ZccTAMiFktprJoWA4r1Kr2UmmK+2sdTTf61LJAjnNm0\nN1rPMgAwZdcVn6VFow/snpYZMJyLyVecsc+xxVMGmy8wY3VC/9KjsL6VL6x8\ndTSVJJ4HyVdRd1brNUYAzgY+7WCsJvoDR1OZWV2dtS3+tVHTag0G3DU5udQj\nsRwe\r\n=Q0Vu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBmmA1i1gJCJdU0wftSuwY8r5BFw+IKuNZfOQjP+DutNAiBK9zWeQ2bXXsmpbyCEVHRwQddlTjC6xUz76fglkrl3OA=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.3_1597301358787_0.7049308453805316"},"_hasShrinkwrap":false},"9.8.4":{"name":"micro-kit-atlas","version":"9.8.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.156","@types/mocha":"^7.0.2","@types/node":"^14.0.13","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.0.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.2","tslint-config-globalid":"^1.0.10","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.702.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"0.21.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.6.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"e09fc679390a3bf466d2e1e487e763ab37a8c949","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.4","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-oEQAwd4+tYOV7ItXxD22odtUYJQokDpXKUPvUgll6HDOftq3yoj82RHpzx5Mc1PMsC8FESLJXVuhonOdcgDY0w==","shasum":"3728b0d771d7922d217484e4a80b1e17d9e50b40","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.4.tgz","fileCount":146,"unpackedSize":428916,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfP3pqCRA9TVsSAnZWagAA3IYP/1p8kkuMLmA4IDSmFUam\n/4J3rFEi56OSDJe53PvkdQbYIdQIYDyCXVpnPU/Ul5ktNs3z1/KYYkIt+Alk\n+U/oVcMjYcT1aE3qkcXbSLqwGcWbOdb3fFof2maxCCQo+zSddWVuGErVjhuk\nP9u8blY8n3IRHj1136F2nmObZJE7haHl9ywqLi6+UvqlG8GTYgasAtECRy13\nizwW9bHGN4XqcWz6ZHUj86PjeTUB5tw4b8tHjkd9zjaie7bZEG7n6Myfqa/E\nQ78MGXe5iA6gzp/pNXkGISROkg0tyjKyE2lR7JovtO73t1L0TXAQwQzLc55o\n3PTzMvfBlooukXKbxbVDgUFXhTfjvE5sx2HvvJAgLQ3apTW6Uc+B8WNLP/1i\nYQkJ2weK9kwlE5Ck6+ccSUC2sFjGSqgcfrACAbGl4H4FRBbcTijA5cjCUSvf\n67dBQ3lZjuef1xWib0yUtjPctSwGpiC29ci9vovBBz8yDFwX34Go6SjOU5MJ\nAoAMQPaqmehyuBdi4hjCRqDFRDtMxfLn0Q7NUVphXwN/o0ELm3bOLxxB0j6G\nIYZDXg5hIUg03nbgrdGpW+Jz3Qvn//MSiZF7Gmo6J+rAd2Yo9g6zP7SlA21N\nk6A+h3N+Utq42bacGjg9yVQGz7bJPPGxpkoYyH1M0p5UD1yOv5AUNzO8bgYr\n155q\r\n=dRbu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCEmInCapgpjde0166bHQ2Uemw8+u8S2ewemrK2XEOeHQIgMyJ+LvpMzrnnHRzEO8NDc9+1eSaiNRr+aXuCalXaetc="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.4_1597995625696_0.2553055311706929"},"_hasShrinkwrap":false},"9.9.0-alpha-1":{"name":"micro-kit-atlas","version":"9.9.0-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.7","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.159","@types/mocha":"^8.0.3","@types/node":"^14.6.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","get-port":"^5.1.1","mocha":"^8.1.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.3","tslint-config-globalid":"^1.0.11","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.735.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.24.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.7.1","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.7","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"913951fee34370cf4962aee2adf727a2b5927668","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.0-alpha-1","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-A/iwRbuBkVGAJyPl8352stmpprGI78xXfoM6JCEVDvmJQ+0ss2zIqULt3sqvdR7UCTgKWhCl6/ezHjAuCk5kjA==","shasum":"71b689e1637602378d4ccbd6270a4f6a92ede051","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.0-alpha-1.tgz","fileCount":154,"unpackedSize":466759,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfP3y/CRA9TVsSAnZWagAA/REP/3GaMZz9xBjDXypnkzXL\nZelRe/Q8rShyvjlULbG0dH1StRBDSJNODfiD6r62xeBIVKtYwzP7KxN0Wv4Y\nwXfOihTJ/QgWCZKnLmKcD3K/doY8LDN0CX2LP0JJ2QHyAvZ/HZxeTgm2Ku8Z\nf6iQ9LscI8YhQ0yWujvV4FncPNKyOCJluDTNtPF17bGtvtqymAXByR7vlS33\nSXyDe9JJzve4Xb4rjSuZgWdU2WVlpcWl0T574FDI/IuJQaBfrf+HcJYYnsms\nFX47/m8XnCkepd2yp6g0UarIVvF8nSlI3ydi+oh7jb/DAmYpxi+pFWR5KmdO\nlmc6V9RaxoLJtcJrCnj7p2bgoRuXuo6Ix3xnNVkjwQute9b8yxsFrl+I2WQR\nlP0B81hhDwq1J7H9Ra7YnsKctEQOey2OG6//aigpK2Uuu6j9uCowsZxfycbo\nyFmm7NBcUM2yRBZMVf2r8GFFBx/KNBkP8DZrDbN/0jgZBJRNub5zBCswh01x\nR9FJ+G3eZvpOlzH/3Estwn9lQylHdYM0PuNpFYBFxIE1KstKBTJs5AiNtcfI\nIQkqCt9zHT7/1QUsxKvWqn7FmZex8zFb7hPhkFeSYfs7cmskl0wGelKVlEGM\nBPxRX8PeydX21tYlfwbtMT7ZoQNB+7cERSXibprciv9Xv1KJizGJMhA6NvD9\nJnxl\r\n=VGL1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFFmo5Cuyhk+Hvdf0BfTdhuq9wM7VfzFKrf/Qqs5UYdZAiBLAPBSJ/V3YwN1mBER8plwGoIh8utFpMetucNmq28yLg=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.0-alpha-1_1597996222533_0.9997121137914622"},"_hasShrinkwrap":false},"9.9.0-alpha-2":{"name":"micro-kit-atlas","version":"9.9.0-alpha-2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.7","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.159","@types/mocha":"^8.0.3","@types/node":"^14.6.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.3","tslint-config-globalid":"^1.0.11","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.735.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.24.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.7.1","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.7","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"f6d31a99aa3e0f4e4b18ee171e86505a39e8537d","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.0-alpha-2","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-++LmxduKOtOef7Sk9YvK9Bjut4aE+PXPpkABPJQpbT1gd6/3qiRR9HWUZ0Fc8Es4eueg3MHajOmoP1VInc3E8Q==","shasum":"ef6e1a28856e26a1313f660f785c7fa4ace9bb07","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.0-alpha-2.tgz","fileCount":157,"unpackedSize":470098,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfRNOOCRA9TVsSAnZWagAAlMgQAIO6IRXnRZXp8Uo1sFUw\nAIFfND9YCfwGTm/LxpVU9Q0+hUFoyWY8b4FZPmH/UZe5mK8NuE6nbX9xwY6k\nrwZmU0jjMw7Qv7d9f2VwZjAoW5Aeq+C43/I+NBhFzdzBu79AlxhvuKsy0m9M\n6FrmtDvPHblVxiPIwyTC9ubjwO3XNKomAqwEN4FyOmGY+Tej5LTKghJY5JDv\nacwqMoDN2mHgW1ag4ArfHn8oDSGsLXdN7/A65h64MhdYmTPumYxM3p8WQPK4\nlP8LoZ+fgKtCDYYeiIsR4uSe7nE3sY3BDswjgpxyvRfnAXvefo39pEwLQsFp\nZoSgJpEMLCfF1j9iCDND3CjvFgkH50ompTvJFFQiL5fovVcmRWEbZaJ+gIPY\nLudSb8v3Ti0RxLzvebO0HQBL5c2t8j9p2DVcxrKrgVMynQcZ/dj3vLltiTjJ\n2Ywh0xRAr5T0G14rlwTcGJPgKLBBV7HggBYkYRx9uuvZFys5eMLB+Oti5n9L\n6bGxuiJ2mB8N24apngPVzKHQs/K+Pa5ZLoIB9yab5fKBb2EVaFmoPtxR84p4\nOsXcGvRzzAprT2bhhlpRMtopnW0IPsl7nlvH64TSmH6e4DQnK45SSz6N5USS\nJSEYUWI8yb7s0kuwGHNecifVeJyMkzBSRFLEm66oQayt4BPyWGoPx7OwUt+O\nG7n6\r\n=/+fP\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDmtypuIfh1NILHWMRBxhsnDKR7HssGcsiQdhI8fFOpFgIgVQyUtyy30WJLORUjSrQTbpWuTvlqcA/l+uzNDzHQlBU="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.0-alpha-2_1598346125748_0.5811801383091886"},"_hasShrinkwrap":false},"9.9.0-alpha-3":{"name":"micro-kit-atlas","version":"9.9.0-alpha-3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.7","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.159","@types/mocha":"^8.0.3","@types/node":"^14.6.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.3","tslint-config-globalid":"^1.0.11","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.735.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.24.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.7.1","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.7","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"9f164258e7d1374e31eb8887c525cadb6acf773c","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.0-alpha-3","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-WjLN9iq5Y6a35shihbyAFXxWqCWPEJKbyO5PHiFqhWy4r4ofWAu4yhkngagevuM2jhfZjn8LQqcX8sBLB7AWNg==","shasum":"e8fc08528bb4275189a02b958fa579a473686830","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.0-alpha-3.tgz","fileCount":154,"unpackedSize":468564,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfROkFCRA9TVsSAnZWagAAm7wP/Au4ApLeEMmS+D35vA/4\n+V7Myz9qFuvEEvK4DsqG7UTcvuIxqi2OqSsJaHMpgtYVixDXWW+5V8zxNnue\nHvUgd2rKKr/XbGjXARABcNrZbQeyNwUazmkfU91jeiLHp9Mmgx6aA+5aQ1Ee\nPWDLdhHNAyT+Xw/M/zjeRwzCY4O3vy055zFZgew8HRpcw69lcNUeNDfgctmh\nRK0xTYmKPzeNlWiGnXSNHWOvMQZgN6v3czZufzUVIVG5BNnh/KWaQ8JcE5R6\nxroNuWEutoEliF4p/ZvWF8Iaj5VyzpQ2Ut4kr1p1vi6LhgDcgnrUY/c9s82w\nCXr9K78wnWt2n3VUtNcoaG6rsOH0Zk8ZP6sqHvdhNbsDY0lMDvps/UFvaMIL\nJ+0fjzBp3tgd5k17UzDXmlks7iK4QOYXn5s6vf12oKSqgkOI46eBVlI2VjWr\nvjnxYdB2l6a2AlA4+oJe/31TuP7qoh5xj0VvD+QrzRvMMamP/NdZBXQ2rgR2\nYpojYklSdbFNvEAkcqEPQA4ldg8h272EaELCknJumCHK54P/n0GrCNx7w/8e\nZ+17FFGOBXhwweJVg0RzKRW21tqFSqaVyVfqI9ACkva1kzokWGoJAUp8G+tf\nCUlgLy2aO4it00wjcXzclEJIsq5mkF5UTgYwnn10RA9WGsl1OcThXCaCaDnx\nD8+i\r\n=BbNF\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCY0aYkH0yXPTpv6Ps6b61lEYai6dg0VxUv0EpmxXg44wIgDEbs4x+T3ll2iLwNJc5mUCzSKZ+aN3/h+UnoHSSmt5Q="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.0-alpha-3_1598351620584_0.6215127373717175"},"_hasShrinkwrap":false},"9.8.5":{"name":"micro-kit-atlas","version":"9.8.5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.156","@types/mocha":"^7.0.2","@types/node":"^14.0.13","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.0.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.2","tslint-config-globalid":"^1.0.12","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.702.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"0.21.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.6.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"be9b58dd9e72d480768b49e91145390ea687c23b","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.5","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-uknXqzYlUzm8A47KL1VvdhAgyK0Qt+DzTNudDl5w3Q1WVafOYxdLBjw2UxQH2dkdrJMM+UCBFHA5qc+AHxiUeg==","shasum":"790982426cc6276b109b015c256c0c197fcf17d9","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.5.tgz","fileCount":146,"unpackedSize":428973,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfRRIACRA9TVsSAnZWagAAfdAP/A/Z4eZPiLXeB4z+BVdZ\n+uSbOGLhphG0gchuKr9seuKmITgAs8OrAYCxBhHs6drnynQ46bkymY6jStXy\n5/cjW33xG7p7Saq9/jj4NeR58tRSSFRPnsiB7dQN+oDF4E6Wmtu/a8f2fEHm\nWq9b3Xe8TNcOu1vTqjrFrLPdD19hDoIlX1XkIVrMLeTROmsJlBigvjICuO9B\nnT4DAMtWANdhEA0mINycZnvWxQjV+0QCLtuNJ4hO0BRPTp7q9kPoezAggdyw\nu8bdnd/m0b0BZI2iuQD39GT0BWpljIX5X6qegpQHiuVru4DG7UlJGJThJCsJ\nsyaL33l92NCiW+eStvr9XiDpWuUf2YcCzzlk6ZDoUuFA6CHEyLhFBtjDqZyj\nSsI9fwM25OkZJF1yK5Hm6wBqfmUi5fUdbxiyW8IEMbkglCgvxFwrRUgwKjvs\nbvRtisdUqD4jcUu9B4uMWgjEU4u4So07iYIXgh/uFKVkcJwTzPaSerj0LNzl\n0FkM6sCTqc90ewQy9uBdjlpEGp0hR6EgBldWHvPW9MtY1bEgzuZ5+5iKpfpQ\nhqfoHto+re6sbDudd0tJjaIo10vXSOHtfzv+TDQPMMbrcsSGlZDvvzbbLJK7\nW2N1RF8aJvvgN21En0OURR/iYOgRlHYf4Wnut3gQ9LTSICx5JhtCkxYNrgWz\n1e44\r\n=fb2n\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCMyGd/8aoT6ZZa8JMNx+WXvIzBKjyy1sDx6fBw2CA6wAIhAKU8du7zzy+FIBh5vvm9w8CzVJnN6XNupEQs4UVdiIQi"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.5_1598362111637_0.7385660241123568"},"_hasShrinkwrap":false},"9.9.0-alpha-5":{"name":"micro-kit-atlas","version":"9.9.0-alpha-5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.7","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.159","@types/mocha":"^8.0.3","@types/node":"^14.6.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.3","tslint-config-globalid":"^1.0.12","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.735.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.24.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.7.1","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.7","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"921fb5502c9b2f89ef6c44ad76fe731ed1f3c5d2","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.0-alpha-5","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-+MGst+uTNiD4GoxneGMNVW+pLdcH0H6fvoMfTSAksG8D29ek+vnO50eZeZZK54yWrKn2aBE3XJizsZ8C5DLqQA==","shasum":"f8a3d031e99b08976d53743447c07d283045bbaa","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.0-alpha-5.tgz","fileCount":154,"unpackedSize":468862,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfRgLJCRA9TVsSAnZWagAAo7sP/RB1OSgI+IX7aTuCWJXR\nfYeAkvzQH1yTCsNoHQ2x5jMdSlcm8QL6KiRASOF+vFIc9qmGyLVFzWy56PLm\nhM8LmVCN5NmZOZGtFXwTB31XX6tpMIdwmBz3CMuhMJQjOXVBGtRLzlbob17m\ngkS/9+kwK3GDVJz+3DzyWRsSx6wikIGzgU27Sqt7b69idCpf7AaskniVeydP\naEhr0uEoPZcOGBMCYAMw0WpR2QLDRXxlcDEqvg/31vSY46fFRdvpwARwOE8O\ncPSeo3G0cqpe3R1D5G0EMqOc0hKXvFJTU2Y8BfjnVrubCGpqiUuNq0WIOnBD\nPXMYI1xSVtzOdKbOEVWwHHM1UWrkatL8Yksm2VJgeZWOjK7lfjBflu7lUi32\n3AZPnom56NJAKvDujykrRrjlsQ5yoslOeQx/5YATOm11uKBquIbNpa9EP89c\nW+QBD++T6tFVxfonow3ZNgc4/C4OcMpnJMCxNZ3s7PMtfQQj1Vt1dmy9XAtR\nJUCPm6X3RxL32ja4Z6fp+b4SuwXMvb9cDvLr6xiJUFBy/KmvCF439hO2zIm9\ntHh53szDL9Gc0j1HjSRz8aXdbHV0+165VRwRUQTPEJXXlmC3Y/lOB1+56pID\ni9yBE4X1mRstN3MhHa1EtWyqpmT6kJ9uFzaoha2n7300HAv3h4KWTkAexvWT\ny9dS\r\n=yFz4\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCpWtJ+O3RZZZrkpTDVgjH1ErpOP9IcKrngKQq9c7LPhAIhAIU0yyi+x9Pot5c1QIZKIWgdIuHQCA4/hnNgWQn+n3PC"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.0-alpha-5_1598423752785_0.6852953350146516"},"_hasShrinkwrap":false},"9.8.6":{"name":"micro-kit-atlas","version":"9.8.6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.156","@types/mocha":"^7.0.2","@types/node":"^14.0.13","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.0.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.2","tslint-config-globalid":"^1.0.12","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.702.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"0.21.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.6.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"5293592d0921fb9936cfc1b407bdce9c0a2b2c2f","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.6","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-2yNyGW7T5PfOMUFQ65N41PbgpHvolWTn/mgcoPwL/hB3shyjHCXWUwbyyBat7wKRbDZSSzG0HFiN4PQbO6m3vg==","shasum":"c1380cd0e95e340e2230db19ee96364411123a3d","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.6.tgz","fileCount":146,"unpackedSize":442977,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfRgW1CRA9TVsSAnZWagAAO6kP/AwvqQKywtyM7Kqbvbn2\n61VmlsyhwsvnTm8B11qP6dqLW0gd6JR98wVJJPsv7fDhZYMrlPbSQV08llmo\n08bsLO/aJdfON6rux50IbmVdoe4IMawEK/xqN3kQGVbQiKNWzy57dKUJHmzm\nOo7ZV9k3VjHV01HqvxkTedpsDkwtof6hfkMGD7zo5ZsSrNMT77ULmN5hk27G\nYqqWvj5O4gXmrQ5rZA22Cdo6ZL7B4VQHPw5olz7dguNYijWqXmKCzdXeDtGq\n4iB+JW3dpH6FywbuAU35SkCR9Uuj0btKyA35oexYz2nPEkyT10Klnocs7Xgf\njFWJ1wWusXMyoLOk9AGjILCcGppkwedvFEPpwc0mt19ONkCnFa6RmU4TK7+b\nBlgqwgVZRb7AkfAe23ut/Rwk1Qt7UPx1H+n2gOsO30Q2B5JjhWagGSzy+LKy\nAYcwJtwBuH502wo+cIz+n63S8HDH7aFsvzYLu+BWsji0xldexyvKgKhIqvmW\n4RtfTJYK6qciCAiun/rRPvg4BP9qiCjjvkG52kvluuPDQLzit8x7wzGdKHl+\n2JzbV03i1RIuZuPsWugW9qXNpvQUdlumHoqII969l+Iz5kJq4wc5N8rOXUA3\nLuEGHBqRjP8pwzxMcvAUc5KI7EcPjLR3i+R/4DUCv6Wir3aEy1NEjNhxRPco\nfrFp\r\n=5eey\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAu+SQ5R6IDBVcoADjGLl9yhy1JXVcMVou139cxg8Z3gAiEAh4yRvdmOy2KpF2hYp34CzKni5KjXvLVRBnk4vVZWiYk="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.6_1598424500672_0.8670765959493549"},"_hasShrinkwrap":false},"9.9.0-alpha-6":{"name":"micro-kit-atlas","version":"9.9.0-alpha-6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.7","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.159","@types/mocha":"^8.0.3","@types/node":"^14.6.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.3","tslint-config-globalid":"^1.0.12","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.735.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.24.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.7.1","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.7","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"04ec649d041ce2a9b78174a9fa6cae48e1c7ff80","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.0-alpha-6","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-MMRMCX2HtrDdpIhTjU07aONNDtbrweA9B5XfM1rgD/rgw2Prz555iBZtGV53V5oW3H9nBJ6/MaFOH3AdU5gwLQ==","shasum":"d457b73b4fa0071693efd01104c15a67bca5154b","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.0-alpha-6.tgz","fileCount":154,"unpackedSize":482866,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfRhQjCRA9TVsSAnZWagAAnX4P/ik4J8Cp2lYQC8PjKN3d\np/JGTOJ1A3L2U9/o7vY80JEbns33HEtEQOPx8Ij82KtVti2HpkfUKU3pglFn\ndw0WNk37Ia4O8JmQjaBRXT249I8fl1X+bzBC1fpk6jmO6qtHmjAnbwaSrxA2\nvVl3C3y30Q9msOUqqiG/3BsRdgTgPF9ce5UEAQwp6GuIyelzEtPiEDTVEUm3\nelBlJKT2/5Mw0287jMe5tXSSZlSA535lcGTwXECC9lFP28wiPbaRR25ir0pj\n/1XYRfrLxisQE2ODWIlobr+OARwdmQyHuK69aPzCiONVEuOnvxK1ouXlYalD\nSdwaDFcUyeMWbq9RG/opIGzJcmcTcSt8ZEYzxGhY2TvFL2QbL2rzYMH5k/v9\nbQCuR7DXOZRwlWuOhFXliatmVpVfImwXy6EzVF0Xj3HOILaqSySYwmqV+y6l\n7InE4fb6YroB3WITGZDLv7Pz74wQaYdZscupKRZqNoYKIObsoS0I1il6F6mW\nNzLj5eOReVqE/B2U6jO9CCSuzk0dnGVKdHEmkGmSxwGQefc0sogd+Qirf7Ys\nxEJNornJcoA0lC7mOfyiqegh9iky9IW6HEPyfz6fUWWDm+VJe4SWxBS4QUUt\nF8qGKDpbXoD53VFJYTLelkPeZrLGGXbDxZ4Ohhm6R18vWQdJInlzePAq6sjc\nY5un\r\n=azPc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC1En1M12Fo9JXC+b2DUdoWYps7Zk3ZUz0fZBiifUUdMwIhAN7zoAfhyIMRu5P9+iIFuKgxFh2PeKHWHOuTjtfsaoSd"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.0-alpha-6_1598428194534_0.07831309849668688"},"_hasShrinkwrap":false},"9.8.7":{"name":"micro-kit-atlas","version":"9.8.7","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.6","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.156","@types/mocha":"^7.0.2","@types/node":"^14.0.13","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.0.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.2","tslint-config-globalid":"^1.0.12","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.702.0","bluebird":"^3.7.2","class-transformer":"^0.2.3","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"0.21.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.6.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.5","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"52f4047c4aa7f308495e00eec789b4d705d716f9","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.7","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-a+EZG+DvuqKWmF4k2CC3nrBcKobg00C/+7rYSnJWV88CtJibMUk6mTLqk+ayWV6ItL/B58wsy5U7Sj4WXxChag==","shasum":"d65bffd67cabb461b48103cf9f5e9904c531a62d","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.7.tgz","fileCount":146,"unpackedSize":443514,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfR8vdCRA9TVsSAnZWagAAcIcQAJdRTkazarBzOFyQKsaw\nfyluqwGGpU2mH5dCxieTfr9io5kgYNiueEvs98xASWWiTlhAq0OHULg1cnx5\nNds4o3k37FDbf98gL3AGW3Lh9F4JOFN6x7NU/WRTfuIBQn1i8jhsstHlLFBJ\n/jbMDvpNtWkCknMNcuwnxgDgGFHyk8TKKADBRePAKNLL+EchNITtHIiUsE7G\nDIjexg5SdeZA9zb8TJKLgEHV1vKrZmedMxaMLGlK9e3F3oyF6IGNDsEdIsZ3\nJf5UB7x36QbOKuo//BL4D8SkmvGAoIr/2PNQGaJBQGNc8jc2QXCHvRTubrcQ\nugqSgatmtodP9Sk1B9kCxLwADFzFZF00YcmwqnRmYHM/dptgKmGV8fMF9PNe\nuFUULBhwC6aMdanu6eToOKZQEjaBUw0DihYe+GoZT3fDbvRszsuQ55/3L3VV\nW39hH1tcp935Q+GDcFA1/Oy38GQ0LQo5OiswGqoqZYorr1/gvyHE2GbINOdH\nqsqPDdlIF+DObXarlaVVG6+nnelZnnYM6GgRTKoJpXbO24VfxLUHCcOmc2ky\nu4wxDEkrsbIuDwrEOvmdKa1avkJ0b4YvdI+VYEhluYzBP63lujJntaTNjYUV\nkvu7x25n6DxvnpeBpOSk8NhGqNeJ1HxrEkW8PiolSR//3NjTRzOJ5wApM35R\nFbL1\r\n=6r+L\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC6mGronnUb2T4/32qbAUiidlrvw2fe509prdaky1+azwIhAIfKU+4j9m4S2pm5pzfNchGKNrmontas0cUxYohdcodZ"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.7_1598540764947_0.5647014796012662"},"_hasShrinkwrap":false},"9.9.0-alpha-7":{"name":"micro-kit-atlas","version":"9.9.0-alpha-7","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.7","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.159","@types/mocha":"^8.0.3","@types/node":"^14.6.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.1","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.3","tslint-config-globalid":"^1.0.12","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.735.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.24.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.7.1","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.7","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"226e47617652f6565175d6206aac2b3df8209a83","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.0-alpha-7","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-xOHSHTcOuw5xPxQP+ohmiFxJwphPDlMJe9cjDOXnJ3mLsromPJ8LPYsLG8vJinyhrKCOMghiPglWr/R6hQpOCw==","shasum":"f0165f2eda6d94f727d44f298704ebb60685b322","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.0-alpha-7.tgz","fileCount":154,"unpackedSize":486653,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfTfuzCRA9TVsSAnZWagAACewP/jgvtt/Rbn7Duz/2mkIu\nfkvw86dKYbE6/7z7LKjkKyzmERplPqZavBlAn5AgLVW+YlRCtnjroNpCTCC9\nZW1PjsYUfcEJ8+KHuTU82dvJCKHAaw9eOzag67Q4zMKIpON04ybnm4dYK2Kh\ngLvXU8N/cZp51pDjLvLo+Z84nbZuU1EacqHqte9sjsFJsG8EwsrPtiD3dFxt\nlxrc/rV2Z8l7W+yu2vxk7dCNfB1vzcjpxxkLSdWxCvESVcT/TK6wM6rstbJ9\nAtuLM2beYNVgdQ5dJm3QCYpluIR5G+6WitU96UPf7JUNaWBO5f+MYuFmqjyI\n6qJpg/LZhCotp3jjgtu9zEz6UyCjwsMH0z0SC5TnPnwXbsp2VYNACJMIVYTf\nFa3PgBFFvUxUHvaB4+1ccqtJRrTDJt2nXdRR2+hbgBJjhj1nGv5mW9mih7PI\n5U1mr1Eat94StiAYRt/abZ6y72SReSugOK9VBPr//eMCypNVLG7ZkHsq4Vy+\nge4fc/u4gnH9CM+Ow/RU8Px9OzNJyGb4D/tz2ruZUFuXvB735uNfkL2y9OUS\nT9o0tXbBX6WZJGUH2S0MOVpYzqBymomvJii+kP9gmbtXLAnlN1azcwXR2RZH\nZ8pRfFMnCCu3kUiw5wBXT01MG7ATxAm6eKgmDkcSeeMqHrMDRqsQcVmGNy1X\nsZEm\r\n=7Bt2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAlXkEvl3FYK9x60K+avOJm44Zc0l1mbSDMK7jrp2Gt1AiBgB5roT3gsr+ajiqqutRwZ1CnvIM8jv9MMt3LBBxjNfw=="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.0-alpha-7_1598946227019_0.5363016836382348"},"_hasShrinkwrap":false},"9.9.0-alpha-8":{"name":"micro-kit-atlas","version":"9.9.0-alpha-8","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.7","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.159","@types/mocha":"^8.0.3","@types/node":"^14.6.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.1","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.3","tslint-config-globalid":"^1.0.12","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.735.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.24.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.7.1","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.7","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"1a3046b21cc734201949e0e889c17ce1bcc8eec3","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.0-alpha-8","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-927z+ocon+oha7yTV+kXMXRH9RXltM6TvYyi57i7o1Z5pX/85iAVMj8kawxDMZwCKjKqc6/IvqBMeOqBoGSJpA==","shasum":"d1b025042c34b8a55cb07d3fe99420efc8d5b76b","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.0-alpha-8.tgz","fileCount":154,"unpackedSize":490244,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfTkQuCRA9TVsSAnZWagAA/v0QAILwhMfMxd375MLeLYF9\nMC5zL1hqmIp0egOLi/fj8P5km2MXiCdXAME+e/hC/RJJkwkN5ubmAF1EdbjQ\nxlQA322BdfFLPupIJgHFrkbEUWISf/pozY4sYvbXyUhYbHmciz7bOmJr3E6b\nVs85Y5sSAOPjYNzvTM4mllZlaTnGbXIgIzxA80xSxQkxZEK4bEiusiWf7hGn\n8/Ane6cTCmoyrILdijbGf7Ee67yba/KncUScOaz+uL7YIIwY0VWdwO37+8+d\nbqv/5kCIovghOfhIDCZCvoZUs+o386uKpzQZQLlUbkPuMS71jTHzgbdjN7pR\n69qclf3I0PAbP6DaFNosXiTzi1zemW3QN922fBSdiv0vp9mErDkAuJdzpzeG\nLXgZNrqWhhAkqCPdhL0DsASqfxtR8p9SJZCju9aWv/9ZcdgmHI58brQPEOVr\nUaI3GvjZFF73x+eaq2sdN1vO6MEmko5hfVjfr4lVgkCywH3yOdhdfX22qR9K\nuzeLLE9/Vfy/b0u66oCY1W0le/6Hhb7Zd9JFqcybg3Dwy6y8sfXzINnC3lRE\nfzZQEyBisUu5jF5sbDZYaLXQartpVM6L9ryzRtVb1UzW6NzUBgf8J6S9vMDb\nkTD1ec29jjxeglhd/wTjjVuTHs0PE4EyDSMlTPV/GQZP/sumDe4eNGjQj9OX\neWvP\r\n=Rm/0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCvOlpKE/eKDhtXESAdmO2N+e9iIoaSaCOVJ3PmIcVokAIgSvdMUgCT6ms29lheGWZe8UasjyRzOZDxZmTAUSQMzTk="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.0-alpha-8_1598964781398_0.43595742535988946"},"_hasShrinkwrap":false},"9.9.0-alpha-9":{"name":"micro-kit-atlas","version":"9.9.0-alpha-9","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.7","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.159","@types/mocha":"^8.0.3","@types/node":"^14.6.0","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.4","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.1","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^8.10.2","tslint":"^6.1.3","tslint-config-globalid":"^1.0.12","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.735.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.24.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.7.1","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.7","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"56c1a507de5f33480b285f6441a1d6452f783b00","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.0-alpha-9","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-bSsTemJv2T+j+vjgI2awnqyzKkdL2rs2DrXMz7T0iKYVbFS7uzn87LqXzBFWWj85gKv8+YjFYbYiqkOU09spRA==","shasum":"afdec8470906684d5165fa08e51f0af0081d515e","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.0-alpha-9.tgz","fileCount":154,"unpackedSize":489606,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfUecdCRA9TVsSAnZWagAAleoP/1pQ/oR9nFtMNa8aGv5a\nkUhH5BZqTdAWGx0/UR2DbZ1BWQDVD0eXqIfD+N0/bB1cIi95LveYrHRBwsje\ntynZoA0j/RwygOujFF2Oyar/A+gMfRHsx95/8KcJqqJLwFToPCN3HjCxooh8\npWQPG3RdeQZkswBtfERAZ5pqZ8JqpIPDs1xZPGq2Dtj7A7bBarth3D8Gaf7/\nY3/uCrEwY9sPa44hsaH7U0cmavv98epPhZPYASyAhVjaNRvWVTTdiPNduST5\n+p48E449jfn97DiBCi9Rx9FQrUraAXAdkaBaaeTHCvJ/RmEwXGK3VWYMkP1I\nuTLGOofMxOZAtPqCtyu9PwCByQio7SLzuHWIFdNWMAaDa58yYGyRXDH8VUwT\nPI6Pu1Cvu61WyyZtkwu9dpdkVi2oRtq0DZh1iaMtsSvmGu+cxXldc2XWR07m\nXGs8KSZicq2WaHM0bRO9YztZh3ec0Y1/EtDQHF4rkX79e+4j6PcL8/bREN7z\n6vjN9slH7svBo4XU6GKF1+rtXO+HKGoj0H0a7CHNsRvI9zcF6WokEgud9/HR\nOhJLhhx7XvMN0ixcBGKxhtrUvqmibnPuBipfTazTILrqEvvZyrBOZr5OtmFK\n4f5vGH9++pJUQgpdbPDuMh4smIYOiU+uU6oRhMk8n5r3p7Ol7iDKtZPFLSrd\nRvLR\r\n=BYdZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCIezkjIse25uBrwkAuDGAieXMG22gbOJxzolXu/tb5fwIhAOcIhLKXqGpe66IdPNKoPDfq6KPWwpAmLfBiDBooQqmJ"}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.0-alpha-9_1599203101068_0.09772986393548799"},"_hasShrinkwrap":false},"9.8.8":{"name":"micro-kit-atlas","version":"9.8.8","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.2","tslint-config-globalid":"^1.0.14","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"2290de0da30f491e5aad26759073ecb56f8d25bb","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.8","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-a5NodDVLf5moBzIH/XolYuFfxQpiw5GEKwwMuTihAO4JzZAalJ7SnZ68H51zH5ZRF02CFPiC0lh5w2AYG7PpOQ==","shasum":"67d5410164d0e03b6ea7858d99d031588ea8e235","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.8.tgz","fileCount":146,"unpackedSize":444637,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfUepLCRA9TVsSAnZWagAAVxsQAJwXbJMfoaAIX7BqhMVh\nyqvHjbyJCtTehgcRBnLq13PonMY5YKzQbG7iy9DLe+uwLgG8rsCHEIjOWMVb\nt44Q4xMBQnQYMO34Lcpzu8I+93Qves9GbvjgX3unyIXjGWFQIQCF+pe5IvJX\nN1wL2KE7Vz6Pc8ZVm6iv6TIYQCZVoM6qURTKntSG0P/gyO7qTOcJ2wLMyU8e\nU/mina95KZIyS20nDNsZEEXngQxaxxq63UewX57pKZQojJZLYpexlSgXa8QO\nHFTh/Ef86iS+RvhMYsYa+W0c7Vae8QwFo4OhJqooEvIajCh8QCVF2m1STffh\nOTSy1MCnhS20yTmjmBc6LFLj5EkB5er11xWkdyKBU/Ecbrd7W/lCJyK1A6G3\nhAWJrm1oI/JSikdVGQBit5sI8HusV00vvd5YVdsf70CsR+p9NRK9rCZkgG7J\nn8RQJtc1lGnPjCiL1lM3wgGsleZ+SgxE+BAtwxuKEo16OzsiRfx5oHVhi3NX\nzegf2AGHHEimEygkQk0hS6R1W6I9g75luAQCR5Ai1JcEcl8rDUBn/IO0aYfO\n+T0QXUGJK37xyk6EbLzY1O7Zk6u4P2pV6xmmNtmrxIt8Av2VEAu7ckDcREpx\npBzGplEgM9Q9brOcDprZg+uX1w9eX/3TbvvGRJ9C9NjI8A23RlB3tH0eM2dc\nuhyx\r\n=Un7G\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDsFIq91FOul4n2fvdt9gk6U4GLL5ZjGn110kUUDZkVtwIgRSc1Idjf/9QgthVvDZE7s/3fVBpxdXvMR9KTQNAvA/U="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.8_1599203914432_0.8647877150595888"},"_hasShrinkwrap":false},"9.9.0-alpha-10":{"name":"micro-kit-atlas","version":"9.9.0-alpha-10","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.15","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"9a291a0465971caba11d33575c50071d14fab472","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.0-alpha-10","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-8kmZ/U8zHr2sW8ikGg3BX9vn5ywUPNXfvnpQ0SnGenZD61Jcs2V+brpNglTFb0C+g4ZV75ZyMsfSWaAXNRHKXQ==","shasum":"5f6d0ef7959109310e6b4817e1f95d8a0b614ebd","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.0-alpha-10.tgz","fileCount":154,"unpackedSize":495029,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfUilMCRA9TVsSAnZWagAAvjAP/RonmffXEhoOq3Jaxi7W\nV7fjK0bS1upjR8hyyWDuYKw5VUb+enxro+4hApfgxRBm6wAR53mKjMFoz5J4\n/O0l3eBUVKwdaSco56Clo+XfLbHimheGbZmUgo7xYLS+bePGxj04drLxK1/V\nnt/Hr7W4NKgc1ofI++03+5BoTWX7A1ZCZLYQq9leIjGUrLSeEFzAPx6jFLW+\nIzomDjv/KnKv3TR4dLXgX3i8mq2wzpWrg8/l1bYrjDI0P9IYu4P6uKTxR+K4\nN250MCRfDqzIMh5Ho+xQvKkxcU6pbnMNkkGkOB/sb16D7LTDpKCPV+cQtrdk\niWZo6njb5AgjWq7duEkbDP4+jPPii+EPuuv1ssutXHFtyrxia7fwnjmQ+JqK\nJohNJX5EW58aCptZOT4pXTbDvY1xYlHxB3C0yLTlZFxmRWsw1t2TFyOW01A7\n/NtXxGiT9KAefVytbpFCS4qQvpyT4Bn6bNc6DoWeVV5v4GP95mw7qRivgSIu\nqk/EUrvClaUldZuX9rnlRQYH4nI3B5eaw62bwqeZTs4Vq1AXQcW4LLnC4wRz\ngWmu/rXEgllVRT881GfeNMKGFZ3zKwpINXrHW6XJeIrRc7COulngM2ktf479\n3vHEOuzJhEbUfr3ztevqmpCGicbRDgABvmBDsdD5dZkUzBksgQe5PSdYQATx\nAHCP\r\n=eBQa\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDQYvSra04nlrYru7bgvB+RRNlJlD6gyBJWSMXN/zjrcAiEAu/XgUWyut+25uyI1EYV92VE6yQrgZb1Eroj5iI2b2Gk="}]},"maintainers":[{"name":"qloud.io","email":"nejc@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.0-alpha-10_1599220043556_0.6866782113933059"},"_hasShrinkwrap":false},"9.8.9-alpha-1":{"name":"micro-kit-atlas","version":"9.8.9-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.2","tslint-config-globalid":"^1.0.14","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"479c41357686669604ee1031236680f4c26621ff","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.9-alpha-1","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-av3uVhVW/ecPFkM1IyWyeQ3eaEeMiuimZ38uTkYBBDMapzlIED1Xng++3FNRzllVOJdBU4Tm6n8yeek+Z9XDOA==","shasum":"69c7ba1e8d5cffd9555026a7cd92ad2863900dcf","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.9-alpha-1.tgz","fileCount":147,"unpackedSize":446548,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfVz7ICRA9TVsSAnZWagAAsTEP/RukZCcqClLDZflciYE2\ntvi2rt7/mz1vgHumLuqNXiDU+e8GdeUOtqYRRP7pJEZhCWiTJhrN3NuWrbp6\nTi98ZXtlZ+42D/h3vFaD2fS5LOMbvqseLz/0ffD5wscVyAie8tA+9iyKZWRt\nlGeH+DGGxAI3pf0fZp4R9SlK/higV4vWVpZkZG2Xt4gl5WzAEGsYTjjzq5Vi\nv39EN38IghFjF1bW1ZtzL0BkBAHFdDTR+6zxzkgxrjah+lBxVFtotZH0EZ1s\nJUjM5GPQEsk/6dwSPo4+iZC6C89vug8/2qSk3QSb7v0PGfN0tW0PETBLEpwO\nYXRBulNkGTwfYw03kDIUptSsYEDnCZGjDWLx3t2plalYIoBPS47vBab05Pz6\nQbwxYU2+mok3kuzyuX+PvymiP0B5Li5aZsgoag5QGOmS0muUYTo7aiAJEMp+\nNrOGELSt7V6DzkX/zSaL9BmeJPiJC7r8QRwJ3O8Qzqw7eKUeazbBhs1Ali1a\nF6Uzq3t0OtLUzxSYdWtXNG7C0K2N3L/lVO31/Ma43UTRbbYdVLB6oGp/vELU\naNPTQxuesJmm/ZkYXicLsuxzP3eqRTKQdJnwsj7jJ6KSWVCKKbROC45kuPEe\npVG1khdvQq7gyh22heOy0usY52gnrUKw8mM7usPhBUAGmUn++GiCBEA4YDyY\n2rDt\r\n=jF84\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCitOzuepQhHyx0H30l4iHOcTAmckg1EyRnUp9BkrdYOQIhAMhuYlJH1waVckAaJ/yCh1F3MJJKvXfeS8HxaMdCdh1O"}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.9-alpha-1_1599553224363_0.9459073551840542"},"_hasShrinkwrap":false},"9.8.9":{"name":"micro-kit-atlas","version":"9.8.9","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.2","tslint-config-globalid":"^1.0.14","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"989dc14ae3dda7c0d9e8d77066d7e7a376b44c06","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.9","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-GFwGG2Anf1cicXqxN8/4UEIXcYxcbOFyHIp9Lg7bWwwm8Kqc8Lxvwaip6e73kO1f7aSrE4F3m7kdZnGQfG4jDA==","shasum":"88f1e540633e439844f035cdd70f612f4fd9b437","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.9.tgz","fileCount":146,"unpackedSize":445053,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfV0BrCRA9TVsSAnZWagAAkl0P/2MyqhGAjJzZ0Z81yqD/\nOF896MhhXGtp93/HiuTHOUqPucVowYWK7Gb4erhCKVgsZnOJ5lRlS3Pi7uK+\nO5viKmtza22OJiMGEHMe77sIzQFZXOL52KjfoEdIKC7dKZqGWIQbMoQ4f2ks\n74bmH79kKT2ZA+53kr0cTxMVUYRS1108GyYqI8nd1sUldT6O79YFzP64qWGH\nqWmI2rUTazdLkBNj38d1JFlR/6ZH+p3Kirsnf5q6cL2fbz2qQrYP44lkYS7g\nmNZKXLk2koQZvupRum7jOIFjym0ri4cnqFmih6QWySgwb1S/OHhbpap1e/5B\n7lFZEIZQuspMNjDCOteM2hYvKjuYX1QmqwbmPlGBbRp9pcRLMFu9PQFEVkpp\nUKkQLtbkwKB6/Z9+M9Ob9MfwRc2+xRLED76uZC+XlLJcPJ6P9nnKrZ6B6K//\n/BgskVAml3yK0BeLTFUF0eOLxEDDwiKEuL+S/+WOZG6qil41WT+r7PsbRNtI\n/qMnpK1cy8+11sWuZFFkCg8j8hEJ29deBHYYiqSYNF3bz1I4VLEC/bM2LIzw\nhwMKhyVPdMmP6zJ4GUaLiq4zcwnldvmkGqens1IKJ71Jz99f4tlF2zfB/obb\nfYY0aZZV7drZRyZR+NZQora9JGTF7k1uTGhAkZspEfb43kal1AGJSiV+j9Cv\nBAdO\r\n=FlXE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHsbiE4duwHIyJyY5m+t4CjwDccpriLvLwXIR+LJ2+HDAiEA6jA1jr0JUlZKEBuWHWZFCzsTPzecWVSRHDk4jIXm9PY="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.9_1599553643296_0.4389519955210768"},"_hasShrinkwrap":false},"9.8.10-alpha-1":{"name":"micro-kit-atlas","version":"9.8.10-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.2","tslint-config-globalid":"^1.0.14","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"cea60814996d84a04928725bd5692bb936ac24ea","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.10-alpha-1","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-SBPwZ0zMBlDap7NjX4z/OQCqXSclIKGCXF67Qp91ZEFxgttRpbUDpXCsbzLas3gUYtyUSZgSAtuI3wm8EmbHVw==","shasum":"8627a024e9125518456b9d164cf49ced2ac1e2e2","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.10-alpha-1.tgz","fileCount":147,"unpackedSize":447742,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfV1kLCRA9TVsSAnZWagAAnSIP/ir9cSFklH1vBBOnRBZX\n69HEVsJW8W4+WYsqoWe7A3eMy5WgApyGwPLubHcbkeiXGh9u2M+QqOCR/U+Y\nPSkFQoH077d8+Y68/guH2m3cnGV4LZK7W8Dm06RB0dHNzLHL8zu8QlkomL4+\n9Bn18jHwvNBI8wFEpC4mLxy5mDQqbCxbdxGgLn1YhaBhaCsJMKOClBetZVXn\nQwE2AtphnOvgT4mouLW12y1izV9ZBDiP+KiF6P69232ftVWqb+95VYbHLoKZ\nvPsFpE9l8169sCxnAKeJxSKnsbOnke71w7JrIMNWpyv80m1gSgwLqt0Ojz7F\naXSmQmXfJ8PQL3Q/jfAogchESSJzOeEY4EUSUueIZ/I5SQu3D53ug5b95KW1\nUir2nS3pytn/7eGAWrZ09kXpR9hZm270Fm/CXEPJiwmi8mc2pKWuYXiPyfsK\nrhZPpgdwVbdmgd2JDQlqd6gCi7J7X5RKdGFRTuTDOssy+0vYU/H9OI49KSkj\nC6G6BPn073RV2ZxZQzQLTL9SmGAVn2KxsiD5uVDc/Ui7Srx4rpirJZVyG4VV\nzwfYzsAhTOy/UrK0dRPwIcx2Hgk58XKRB0THMNYZwCfPTHsmxO7DJ6r6Ijy7\n1DovkTokNWd7Sd7k6B3a8nr7RvAQLkXrqEgEc9kNvbt0MBossA9lK0hr6kWE\niZKs\r\n=rQBv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCHI6gJnvenm+p8mP1d+PUFSXw+Q09XeKPxj3O+/wkSzAIhAI7gvvCraNJnhsd4IiX9x0qFjRhadQaWy/iD+RdNRmKz"}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.10-alpha-1_1599559947236_0.7103380805276851"},"_hasShrinkwrap":false},"9.8.10":{"name":"micro-kit-atlas","version":"9.8.10","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.11","@types/chai-as-promised":"^7.1.2","@types/cls-hooked":"^4.3.0","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.16.6","@types/js-yaml":"^3.12.4","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.3","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.9","@types/umzug":"^2.2.3","@types/uuid":"^8.0.0","@types/validator":"^13.0.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.1.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.2","tslint-config-globalid":"^1.0.14","tslint-config-standard":"^9.0.0","typescript":"^3.9.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.2","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.15","micro-kit-aws-queue":"~3.1.5","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.8","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.1.0","winston":"^3.3.2"},"gitHead":"17590bd05b6b762478780924cbf8d5c0333f89b8","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.8.10","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-q7qSiCemk8xq5UWE+hpYGuycq5aPeTdMnZs+KikWQfj5rPIO9Wh5rDYq2Lpel15WSlOnzoFy5Nz/l+BgM6D26g==","shasum":"a8d12e0aea9c4f43181a358f9541d45449273cf3","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.8.10.tgz","fileCount":147,"unpackedSize":453257,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfWIXQCRA9TVsSAnZWagAAyusP/3xMAFF7tmYQPYW/mAXj\n4lXbmF8lGCFw9Li5IhUgVXFSLmOP2UmjUD4ULf1X4ZmWitpxvf/u6E/CatYQ\nr5WFD6ccVe+ILWnqR0K26GD9GpSZrdhEo+aQjsY03I92HmG6tdvsqEwGlGZT\niP0KlBWU9Yo0r7n3e/t0+lRIXoRb6TsqK2UAvo3GU7gRhl8WEGMsGu4UiRrQ\n+83moBjRteUb6SJWsiE1eu7DdLv4VN2Vo7oi6mqTjQ+HO6aFSCfwNvU6M+ng\nNVoPma2txY2n4k95z0tBO8OlJMTYLMkCiXjqZ4nfq6aJan85HAQ+pIKsLXa2\nU5HE4hqqoBcLhCghEFZRl2SWh9LiknvFV0RMn6FY8ZSR4VTDo6D/MagSeSjF\nRE96IjW5aJ6pvKySBAzdPyt24ZYS4OI4BDHcrIX09Z+EHQdcUtszDuIz0t0s\nSADEJf4bCB1zAW6M8pMvL9JwaWD8oKwfujItVei+kJtH+ltvOqh0/z7+vKxF\n3lBIMsWmZDR1MGtztPeTyL4DsvyNTK+EBfs3KOz6fZ+OvgaX01jgxhGcCUfJ\nk6WxcD4IOcWlTS88vTOZTm4EN+LPzuh7hxZnz+S0iJrfltw8L1ICma+aOGjg\nXxlNLxmca2Gs/XrYd5G1+fDYHq5WO5LC4pAsUzUEY+GLLW3eGApqebyP9Ykd\nkvsg\r\n=0+ql\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDVcTW5OOGuLREQB6CqC/APTlnw+2T37TGTvnPviAp2GQIgFY5CcPrQuaJfNvc6Dw+nfROSNlrW6TkUsxk8tirECKQ="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.8.10_1599636943966_0.9273981291474374"},"_hasShrinkwrap":false},"9.9.0-alpha-11":{"name":"micro-kit-atlas","version":"9.9.0-alpha-11","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.15","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"7ec2d377a3260a5f7b4aae55298e8286f4784a43","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.0-alpha-11","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-k6P6SK/JldeSJ7IHyJORMYHZayuI2JUsbDjwsB7TAkS+1K4zL/tRhOhx8ldnZVSq/AAp/ruDl80CkfvgSu07pg==","shasum":"3217b58294bb693cc005a4065ce984369671879f","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.0-alpha-11.tgz","fileCount":154,"unpackedSize":503363,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfWKwtCRA9TVsSAnZWagAAdRoP/jraKYgQmOEvPrIEqkmi\n6jZbRh9W9rZO/pb+sAqGzHU51VUP0BYMh1U/ZvSc47SiLBsJvN58CeDhJ9To\nTxttRf1F0J+zwtbBUcfC/6d0PDntgfYdt5oin5nXRH7Qofi4I7BY1nJojnSG\n1i1Z/oDT+cnU0vrxXaiuMcjwo9yyHTEXRJK6edLWvmySRjcNEoPM6vPy7bEa\n9qCebLKnsW4RhJth3pEljM9dA1t+Uw/mD7wbeBsX8ennqSWWIfapx/yEzYFr\nNPK7a7+WsHLHSNrv7OQzEKfk9poJbiUVB9IWUc1Ovxp/GydGq5vaS29kDiLB\ndH6bupwoX21M+3a5T0yVyNxOLv2hVv+0D2yU65ZzGdVn0STypS/88holhbO/\nVe/ERwyvsZhYjc6VzlhXH0YjqpCjTfA/GjdNlUe4+suuJiI8synLNQ29exxf\nmpcyRAErruJyOd3fqjdQOB9KKZhF/SUTNW9F+FJ61YzlThaWcfQz9WYTsMwu\n69t0xPyxabV9C3rh+/e+CY1rTR4rWUQDVp1Q1KyzSvWjC3HEsgB3ajCRzzIG\noWjD6looz+RM6L/3YWT97v4aru1kKRxgNHp85sRlETX/XL8SuYx59ia34X1O\nRr2s3agt9sVKeVpvp93NCl8amiH9fF8DL4SSVqm7zM3Tno+9FxOm18p5jENc\nhDTP\r\n=VUGu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICp0rBZhsl5JDHEDqba0CFA01rcZugKxFCulFSL1T9WWAiBoub4csA+yE9C1G5wunbpyHT0wECzBNAwsvUJamYAaEg=="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.0-alpha-11_1599646764348_0.7631181136820819"},"_hasShrinkwrap":false},"9.9.0-alpha-12":{"name":"micro-kit-atlas","version":"9.9.0-alpha-12","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.15","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"3d891c192a6c255a78bb6d0aa80cd0b4aff8b5ff","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.0-alpha-12","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-WS0fUab27VyNiKLTmlQE6iZrUuXvBnQJlVm+q8OcSOSWzEdXH7IFEaqLWg2+vh+nnRrats+xyvBHt5K8HylsDA==","shasum":"402f1a6c0056e16a03e519cb561559c740c16e48","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.0-alpha-12.tgz","fileCount":154,"unpackedSize":503790,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfWPnPCRA9TVsSAnZWagAANrcP/RAHGny3P2BqHJ+mDo/W\nmmWbFx5vYRYu0LDSuhqPJ0XY0akwqn2lZ/bo2KFW2QKXKah9ri7EM56VAMxv\nwmbTxGnXBgIWV/oFQIMkXn9kMUgcTMjtuBombm5yodBT1+FGPHGFlyOCGdrt\nxauGfwYf2bT7hA0/kThRfr/ouAbLXJdvG2supwGxJhmPPpXL7H+N0+HpL+s6\nQi/Mo8zSraxhbZcow/uW6aXUVyO7psp+cQZk1vRvRQCJB0bSZLZ2TDlIPVgr\nQfr3yWh3+WDkRaie9gWvA0FO4SPWwiyOI9es9i7/hl3o0QvS6wYVn6bhbnTa\nga+J7klHBA68VG3z3fcnto30r6hf0+f21zqK6YgKNzqQxNo7oTmfeHFjXuhU\nJROOwzLIRgApNoKUWTmKyWhr7BMzdh1qhCFcPQzROeMloyzg1n5z5N4CssAf\n8rbHRRGa/OK8CahnTunTeLu9RAMmg7IZ+G84WRM9+BaeqvBrC27XWWLKJxPR\n9ObzbZyLTklXpQNF4nqRUO4mhn93eQxJkP7vybczh+Cl0Zx156SR5z5z4BwL\n/OBWwsIqfpp2YIwa5viRzvAy5+1swgjbPF4f5ehslwWqh6gVig0Ws3W+B4e3\ni5j+1+VpCtI4y6GonoiVN7VLi8Zu6W3psRbggg5r4/aFrcgev9N9Yj+PH8yz\n3mD+\r\n=ZWpP\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFqv7uzrODDjMdAFnv3W4hw0Jj/aOtldVCr4AB5XfkO3AiB3ezZdoNaoBai/yaf2TP/Fmb+fhc/FXSwsV6f07FDHhg=="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.0-alpha-12_1599666638451_0.96237341499925"},"_hasShrinkwrap":false},"9.9.0-alpha-13":{"name":"micro-kit-atlas","version":"9.9.0-alpha-13","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.15","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"2d3207f2c06a8355aa4ee10388303a86ae79dfdc","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.0-alpha-13","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-ddQl1FNMV9XYCbt9T8H7t22+aXUsWmMa91WAuJSPMVmV4wewIzNOFKck7zgl+HHTxzzCunyXDkAveuc3AborTA==","shasum":"2721b91ffce75cd5cd969581818972a08881bd62","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.0-alpha-13.tgz","fileCount":154,"unpackedSize":505994,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfWoSLCRA9TVsSAnZWagAAGuIP/juRjXyD+Ez2Dyosi4vz\ndNvmOTnAvB0OMKN9s8vt0FopT8w6TzBuvo756K52QgP8iyhVD0E0XxWB85ZX\niWCyDLIADo+UiF0vVwlMz6pycVYHgabnAhU93KMx0j/cXv02stMLNnEvLcPl\nkFf6VK78julM10J0QjuZnsubGP6QlJ7xbvSMPLHU5JCm0jmwT+/uQ11+Ts0b\nbevhsAorQ0rKU+plbiGorD9cFem/s4tkH0lXQUObLyxOF5pLCFloI9k2NKID\nbXm67Cn7KVcde8JrYqrij3DRkxDxZMhc4KXly3zQP5HOvy36aQaqXMT/XRwN\nrNoZ5vs5vSX/nIOMIaR+CoSOREbwGaRCRK5cvkp5XigzwEBDHflbfM5e1cIi\nsyrEMsHp7FyofDKyf4SjXZJ7qHtMasWk7dZV4bgV+ODrqflM65yR7IMNzFtd\n7yfYEvKmQiI39xz/B9GUOev5cgDdhbaN+ewYjCcN6ZcBfgZFRVElhTuIowuV\nRwZ5p2mXgxG84+lYvkZUtL6lKYg3gamurMh9xHWCP3hApEqfCpWz6JTd8Z92\npVTsdtMrMPqv4xC8ufc8+pzzQWOk3w87697pPC+Avcc3c/EPZCSXeUItDwPj\nI54EyNhcMulDzoLDqJOwuNR+DNQJdNkK7kFv/9X7M61HKkymwXb1GjKffAvg\nhiBB\r\n=T6o3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC2MsbrG7hCg16iKxa3fShcloWsmMzVA7rWB8kcSh0hmQIgS/k/K9/BO5FThrlJDUZxUiAHkpBxyIJrfW+S+Emy/cg="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.0-alpha-13_1599767690233_0.23646459455014335"},"_hasShrinkwrap":false},"9.9.0-alpha-14":{"name":"micro-kit-atlas","version":"9.9.0-alpha-14","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.15","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"5f03dcc07204e0873729387233042d71e30105e3","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.0-alpha-14","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-0YA4qx7/q3LgzOsbotlch1wjPxvyWciVHzkhYJ1Z+QLyxiQlrZGRh2Zhv5dLJu6ChjZSh3cDtZYunN8JdM6BLg==","shasum":"51ae129761dd3a06b2670fd77c2a5bbfbce1ce55","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.0-alpha-14.tgz","fileCount":154,"unpackedSize":507063,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfW4I7CRA9TVsSAnZWagAAqa0P/jHAJf0DVoAW+J/V0mc7\nF0y0Q/2DSv1DpDyR5d5PCVzLdOhZwN68BYD4Wz0fGfkpdN1kiM4XHJ3eQvJX\nEth7DESasl0a+fxyYzPjXKO1Qfu0sIFCFx2K3zdY6GxnbXUhxEkyKg6BHNd3\nHGiWmmFc4qphH3ygDItcsHhSpdG3oOmHJ4KoQ1mynlblWDQJGjt8RDBma022\nRA5KwpKzFtNfCVi3D+Elz2T7OjnioX6gbUH+wpD5ehquwhzf7iS6MTj9mQea\n9ycQs2Jx+BaCqBb+Ycd61YVwaUWS0aFJf7j8XM43yEWYEeVWTSuLkm7QWC1g\nVm3sAV8p3o4CHM/jb35X/xl7WeYs4lw32Mu2N0i9zmKyguhi/EzaYr3AMZLG\nTcIutxgGrs3swoGgCSb5DqyXvgICYji2LcZnMcewIjDCJ5kbMjrhTpegtOfq\nTk1yPV2WIeKTlRWjexm7SnIEhx+4qDLJNkD0VhidMBHHBLdFjqRNZRs9/YnX\nHuijaadZPhURW0j1DK6qZgdpJ1auA2sK0ktM/CJmrGraNJwMFCB+kcqJqlcP\nCAEzb3Ng6IFmru/xKNbFsHO3oCTAcbtEw0qvVL86oDn65lwTyg9zYnC/pf6U\n6k2zQ26CptsPisB0GA5PbYQf9eM8PhXLgDMiOjLaI0PnQ3fTh0bOnjx+JlZ2\nXJc8\r\n=aibz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHVii8bKes9W6PvKC5Dwfk3Da0b1mQ2Xrcz3ZmYh/ywhAiEAtw9bNmFduIHb4k5CYEZM8KpoNHBFLW1GvwJL8P8l0VY="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.0-alpha-14_1599832634410_0.20553807854882544"},"_hasShrinkwrap":false},"9.9.0-alpha-15":{"name":"micro-kit-atlas","version":"9.9.0-alpha-15","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.15","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"f3ec537b9f259bccf9b72066164e838248316ba3","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.0-alpha-15","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-asXTf9gQPiELLgHVD9xJNJuPbQHC6KHKp4/xnVTuJWsFAem5ikkMQQhYFySHTIYqK8/Gek0nr/rIMiy7RcagRg==","shasum":"6714b720972d46209c8917a7a3c1cb99090c4bd8","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.0-alpha-15.tgz","fileCount":154,"unpackedSize":507230,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfXGgoCRA9TVsSAnZWagAAee8QAJywlAwXBFFnJhZYpV4f\nVfb+tGFJ3ByZFZbHtf96ntd+uQR19rhRH1B0c/9oNV6J0XzANHIGb/jr79Wm\nY80r0nc7VElWddBZOY3Ht1N4HPpmN21EIsW1L2cddG93MTP2ghahUNRQac6Y\nHRU67Ikum2JkI1mwQHHR68OY54LSryYaZOzdNGYecBD4lsvn8KJK5v0qT1pM\nn6/+BgLPhVXt06Ifq6GICjAw8o4wRF6OT+R5c3EP7KbCtclk6TORg0l5PxPu\nct+9tz1ckuVBIofxwzB0FRAwRjijkRqPy36tAUCQxvIgA8dU3pQu6sn72mxa\nVoyx5hWPreD9ETcBrc7S3zpvRk4PGNTJ1c6pNpIfTjoKPnEjVSKzqAO8EYSU\nNO0ego6AAHdF3w7sFE9vwYKBquOPN+V6K05mQIlEm8ZgRIAeOlc+lFw+GMq/\nmodk5zh7COILsj/CeB+UZ5OJKRTIerejb3nSZ++CGI4ArFip3QF+45VN35Vm\nn4XCOn5Sqd3Yk7qWCh/t2aKuMtENsEXSoLteUGT9ERbsyAPq8BauZdnBX+Jt\ncwjRFaXp1GjOgGriDDd/m2/T+YjWgROhXFqko3YFn/RJr76PhxuihbHmzY3p\nX8eK1ZWX/5H+v3NPFKgbqgkU+H4AkFseFKZ/Yyy4HWgwGTUtSRsWk5Z2xNph\n6pAt\r\n=2OxZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD97eCmJ8E2AtFSTlz8SeAMqNN6em5ILbYg13zex+s74QIgdqMVKF/09dTXzVmS3TSFAWHIy3vTL4+r/e+zzS+FVko="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.0-alpha-15_1599891496305_0.6396054078683984"},"_hasShrinkwrap":false},"9.9.0-alpha.16":{"name":"micro-kit-atlas","version":"9.9.0-alpha.16","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.15","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"019c56ae3223317d7a4211d29410c1c884208205","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.0-alpha.16","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-rfKWe/1RPQfeg0T5MfQ+1O8eD8xcZv1TuRVodqllYuePlT/Ql6zl8e+ScgOc0XTebnSJkE/anwAxsuz60iAvlw==","shasum":"ba197645149db901a03f5ea14c20b0e16757b0df","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.0-alpha.16.tgz","fileCount":154,"unpackedSize":507282,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfX3s9CRA9TVsSAnZWagAAlnsP/R3LhCAoTi2pVuRCIaw7\n50BegbkEHEy4aN5vYuOxW4VkC1uWkJ5pD+CzXolpa1M1bC/GlLZLL7S4IMQk\n9xoHGvkzH6XDkks3eGKszDyb8UomhSJZrWaV5KfP7ji909KcDNwC34XfjDYc\nDIwNz0/DhYrt6BfZdqllRVWP+VBMcUjIekk/6Qrexsp4arzSOQQ0j9AvozNB\nrMK/7YBEaTgJp0uO9lw5tw/pvulcp2pTyqwpLRGJEtT9wjEeLcRSyrvIW9YO\nfOzPf2QY2wNO5Xkgk19CSjAQm+2V9CVslpJrobM89rsfAJj2BFyORMIPKOdX\nuPo2SEZETbaH7ZlanJb2j46DzujSJ1vmPZePSRFO4tJcwteOwV0vOAbcFsDb\n8NayXycLvRehR9xxcR0a6fQBiLsg4QBrCQS1gknRM5m9G3UKwfZzHM9GvmnV\nJxvdqGzqFxCQi2C7dT7Va4YTSFnH5+BK5e0EpjJuBPMlI5k93Oc6XBE0bGQa\nVwh6jlmPiWfAQzAoGXWtQbSDkgoUFKVQLwWYEjk66b5skF/HEHYrhFv3d+UW\nhKWP7mW1/t4bU2r+be4mTPeqb6BXB6IsM2LXRs5vaGdcWwuPTPV4CXKBcp5G\n2+e2GcF0X2KCEFraXN+DWK+xf0TeOr4hYVmFlVQJbtbbYA5naDCV/68Rehvp\nmcdy\r\n=vjUB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEyFIj25gNeA/rp7QMw4SAlkc4YVYdl2rGDnDOldWtt5AiEAlbeO8D7VocPGCN/4eRUf72UeM2STSQxokKbbheSD0U0="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.0-alpha.16_1600092988533_0.9075792840622487"},"_hasShrinkwrap":false},"9.9.1-alpha.1":{"name":"micro-kit-atlas","version":"9.9.1-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.15","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"c4f17b907b9cc682b7138971f3df9e6677428975","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.1-alpha.1","_nodeVersion":"12.18.3","_npmVersion":"6.14.6","dist":{"integrity":"sha512-+VZLcVNFYZi+xwkqQceUHk4XI2GkpXpK9X0C9FPmuB8yxTxynBdfBsqjHhF5Tc5qx7LXRNUnB+KXGuOY6eGPMw==","shasum":"5c8b430a9cf3c1b9222fb93ec985279217405b3e","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.1-alpha.1.tgz","fileCount":156,"unpackedSize":516445,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfYfUgCRA9TVsSAnZWagAAbQ4P/0OQ4l+oNHsKAtr/4Axg\n0YehwD+J5z2tNGCgivdsMtJkFstg565cVyXZaQUr+LaeKsFamZtXOkZqm3Tg\nwVsV5UMpwrNYf1aavr0VwPYPZKkXU7XG+S2grSf8TA8FYPt6c2cy2PKX5XDg\n/SgmeGdGSJlrydEjtXI6M914MGTPI4E/zT05Spr5PH4sxevSJ7s59tq28jDw\nt1np31BlEgOZvjhMQ5cT73JxvUgCHrap4CTR1a1kVO5sVARuE40SCPHxOEOD\n12Xy9gRohpd0mqBwET0qIhZVwg60puY5m6IVr9NyzxUQQFo9yIqzeAx7eMLV\nlZLbLkP0VZdS98KajW+vSGtomTHUWOc93ble1RZnEG5lILazFF99MeILQRX9\nMPkV/sc4U7rqBHHQh8WFvcnKfWaexOZDHTqlqsKe03RSfB4x2kSddeSDsvZc\nXGbVoBM6fUAlPInhxB6UQr/BffRn9ridhnCYjaW0jn+xKB2xvI3hCnQXI4ab\nPfXao8sJQGYoS2wNbm9owGS2ADHE0shky3TL1xU6CFg9CWOYtlTQvcgOWZNQ\naAV9M8X5tt1GHvf7FlLpLX/2APsxcUqVLyc1gQU+yNfx7yRFa56u8YmuBMQR\nTCH443GaS/MKWF0kvxbSDcvhjlXlTP6JaP5yFcuDL+tmJHEEubgtCir3ejMY\n2fTO\r\n=JuRJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAENcnkNs8um09pkHtVQFsnOgMPF0N7c5jl1RjfoyfFdAiEA7T6oykTFlHBEkhbpPmJe0VlUG4ekG2kbDPn6bqPiHhk="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.1-alpha.1_1600255263741_0.776025467211803"},"_hasShrinkwrap":false},"9.9.1-alpha.2":{"name":"micro-kit-atlas","version":"9.9.1-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.15","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"b2f712ca099af7eccc8c8e0e63e4d49bda0a0de3","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.1-alpha.2","_nodeVersion":"12.18.4","_npmVersion":"6.14.6","dist":{"integrity":"sha512-VTPLXcT3T26x7gBc234qiAzDrzkfjrjqmQwOvsfqFZnmboB8C5/wGm5usmEjhkLpjRgQ4ZFDiR0+fTAqIH+4Gg==","shasum":"d5e7d6d1649f4a45a8f55378b690f03bd0897261","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.1-alpha.2.tgz","fileCount":159,"unpackedSize":520718,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfYjUvCRA9TVsSAnZWagAAeIUP/iBYT583MGDotASsLHnt\nclGB1Y27+A6hy4z04Ucq+G0OeovPHgv5lecZHTpYAKrnCNrwVJF+2AZ5IwPx\n/2KH0Vh9w38fxOOIZUCMhaqmXmitYx7Yd/9EYp75SO6Zkdg24CWg3zjXIHXq\n/r4+km3pYrzr6roWvvd3xgf8ER9cOAe/GuP0mN5cepdrlfQ60z6DZ6/KPS1S\nys2aApZoo/cnVQTx42kZCGQwcQTg7n4LVoSPvpobQmAyuncJw6kqF+tFCtIn\nqIIni5uBqq24axwF5eQ9N3ZPwoSOUoLHFIspNhr2sNrP85/uYg2QzQY+aenP\ntcQxLNfpJ9/ZuTG9Nnwo9J+BrGCQ4hkDs0Kohw+5br1FV0smh3HDwKDv4stA\nlOLSacCGrM7s4zrSEbU94MpvAtoTRs2VC9Wu9/G7orurd4vx4eefPiL6JIAc\n50/1mrltrVcl6o6DDfeTtTcFC8bDL4Zp0xLSFiONHTE0xT/XRG9rZpRac2Aj\ndEAE46UC+UZWT4flrp5lplgtO4pD7IWv8W9w+dR18YGsIetNddt4xRIBZKh2\nm0r2IZ4RNBQEtCa+IMh/dQ8vZyClV4Gb3aiyDGBGsletvKoIpcGN2w55cr8u\nJO016yDsh/hnP1xfCiPiTpYlRUK2TSZZFNXDntsxdIyFqRaQLbV3vxjDeJL2\n2Zpt\r\n=kXFn\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGVZU2IA7ltmIDj2if8wUUvJlsUUcYzoLaLKfqdiRmCvAiAQhUYEJx6AgSNGG5u22MqU+3gH3TMc1ZRovgUubx6VUQ=="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.1-alpha.2_1600271662442_0.9390763361542307"},"_hasShrinkwrap":false},"9.9.1-alpha.3":{"name":"micro-kit-atlas","version":"9.9.1-alpha.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.15","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"ee1c3b46c3394dc205b35c6a8ebd140d59ef1c0b","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.1-alpha.3","_nodeVersion":"12.18.4","_npmVersion":"6.14.6","dist":{"integrity":"sha512-VP1ccl0tJSSdDKJcvgnp+T+rGAX1AtrExU9iB1BwoDg39k2rc+lpKOg3lKgNGeidORb1SjgWVkuFI/0Ley74KQ==","shasum":"ebfdf5d3591f6da271b53853ebb29c6466417b08","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.1-alpha.3.tgz","fileCount":159,"unpackedSize":522959,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfZI/ZCRA9TVsSAnZWagAAOM0P/3DIJhZ/dSO65XiWL6z/\noanNEW2fLp9hNSpQ4DMVA93hXj4D/94qEvvHlIlNn/xgPq9w8wogM4fYFyRA\nYf2A4A8YymskZsEGGIbDlq7b/GtV7Z2kSYfjVwJQsVS1/hX8XiS2bsQROcOa\nWY7YAHzz4ZQj6/ELVXrYpZxx9y2dHtic6v4nmd2uvX9VIxJpIHCsI2poaWBe\nuWBdHr8WdTI2QUP5cbTbkuCuTkxN3E94eltvJ/RpQ+mCWZDVvqLTdj0vyr3m\n0QbVJ5B41/dUmYDgujS2K+2RELsU/tLeEZlKSzjrMQflqe8I6WZOmx96esAR\nfGsHx0pa2Dcp19jqhuT8Ak93QfWP4+w7TNwJyG2LSiKW4ZOrsX9AkAxKWxx0\nQxdJArboCOAj1fOSGGvKvGY9/Mwl+fZyB5cNoRhRBQw4TIM5qGsm8pMBVU/G\nYqtEstdvfRzGoKsMc2zgsBEDZKUEmy4gBxyJmqzcFie8hOCYmnlI3gWxNVLJ\nqi46J7dDdAQQr7SRGLQsDWK29oLa4Gmh3MOj+S4NAe0MhgnXCYKtFp9LqrYE\nPjHY0QIU7JDTeLPcEP8OlrXo/cajs6qbfcFzNFwT+EsWM8/94MqtUZkK2aXm\nGpfWm7tggPXIvxNr078C6msgqchHSzX/cAv1h1PBvnbzq4wwgURYX/TnHVrf\n8KCU\r\n=CN0n\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDXxKAFqa+RXoxEVQ8z8HH7JyjXkXN/W2KyaKnNrUg3hAIhANnlVX2tytMyVuQ1zGOnbREqll6tw9eAYsy3rFk7SYLF"}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.1-alpha.3_1600425945184_0.8081228545072061"},"_hasShrinkwrap":false},"9.9.1":{"name":"micro-kit-atlas","version":"9.9.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.15","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"6cecfd01483c0e397a0cf42ec41922c30bdcec07","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.1","_nodeVersion":"12.18.4","_npmVersion":"6.14.6","dist":{"integrity":"sha512-sjwU1qCURn2sdEmTH8PkU3mBpzNRNkq0YdHP1DTHUanBS1cUzrlehuhNQ6YW2eOPBJSIBiJyeGqdZlXG9Y2KmA==","shasum":"2d5c985e3876dc6bbb7b6ad31808f32587b4040e","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.1.tgz","fileCount":159,"unpackedSize":522951,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfaYp/CRA9TVsSAnZWagAAlIsP/2Zh/e8SweTi2W9bOtal\nUoZoY+gdq+l8ntKGGVVIYJibKgj12HW//T7uOoejeijGYln4ZrBVItpEoo2L\nRYuiq5d4pPfNkYAAWy4xQP0dlZomz1TEZQ1RwPGEaT2OseosXP3WrHibyZsO\nV4fROA/7Lr3mAzX7zzSgcPgBj4rJUpXexWKz2NCsv4tpSqhW9dZCYdzdC+SI\nBnrV7X6MHi7PP1qMjqbvz02vliBuSlh/QJ5ajyM8pSqn2f37Lt5OiuyWpeUN\n/uR8x9na56aAQvrk6L0rg2WF+lc1fZIu7JBH800O3uT7fIYTJKtLRV5SQRwB\nA1OqhwRkjK5R5Nzza/j11wYfJgMLdCReR7i8lfD8LAEN9tsLluUJa4xeg3vG\nlvA2oR684grf3iOQgTfso4bYPtQ5umn0/soHVz/e7iNB/bC4IPpyvTAUJjda\n9DXTS1SUUaivWgvAaQkAUPNznXDt8zdSpGUonJOVSeoyBpiGeXWNGVbANXLH\nl8TkbdDL2cAYwOBH3rvnh6xXz0vTy1qunkuaMO5cnJXOzSo37abcg6O3o/gA\nGpb56uUTm86seSE0wccU7HIHQIqkH9GyWmK21fJehe9HV0YAvUmtx5P4BBg9\nzhF5x43sROYQjAsR9mV9wOwvndiFRnjggWU0G8CyClhbjkIr3d9VOb4AXh/0\nxTSq\r\n=nXV1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIH1kXjrI86qh31887Psub+76oWhFcXE72QwdKowb+gH3AiEA87oM/6MNz9kIX8ApFYtOfDYorG1YqTLv6+mZVJqXaaE="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.1_1600752254607_0.16342333815635057"},"_hasShrinkwrap":false},"9.9.2":{"name":"micro-kit-atlas","version":"9.9.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.15","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"330ccee12d6a954694ef6741726da3c315f5d98a","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.2","_nodeVersion":"12.18.4","_npmVersion":"6.14.6","dist":{"integrity":"sha512-pXTXmXvybkblhOrtQVMI4ZsCvBztHJHNIs6WRqeQG3cmAYHlBMvi+FdBikJCEVMFG13cC3QTCUiqysCE6sPGJg==","shasum":"93999b87d103bd13aaf069bedccf5444e7269f51","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.2.tgz","fileCount":159,"unpackedSize":526298,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfcvcxCRA9TVsSAnZWagAA4bwP/2CJ36rN+lTNwTIHSnlE\nakJbAQC4NoP5Qg48dNvSsNZ+7vStOEWrEk0Lipp7hTHjThfNt+GMKmhq6Ixn\nWiobQD3gG37GXpO00CRh3+4Wsgp1rimDQgqnfBuXgCHAkEaYFOg0CgxM8M6Q\nDVJimo4WihZ4aCvk902LfObj7tV1qBHrFUMT4b7SA7Ihe9dm8577YIrKs8uY\nKbtEa3V/mufLVhKor47+4THy0ttfsY2RuKA5AXLaZ0VAjjRt6YuDUqhxeRyD\n3v86Pl9s2ufcC/maOOX7+udh/6cLUWP/Pt0MO2+AouupyGgRCdNkJ/zd+YpI\nRlm4AUcjsC534p4fHpph1dYJp5cPphDxzwKv0TRJriIGkidfWF/qSrPo+teX\ngHiCpv29ghygmooSagVyt0TnJrhLv1GV9STIsF+6UphdKVrybsYmSe/9+ToU\nVMQAx3HEUH1iHtWA0098TH9bH6zv8CNbnQZZOPujP58B64ZwHd+LhAmn3GlA\n5v4NDntQP+0z5e9gZb+v/hT+GvE3lcKsq4Ug7KwED9vhy6+VjdD0cf5Zhgx6\nF4UuGfW5NWwMTQ0D5gDR8WI0QmmWDi0DQ4JlRcUa5bv/zZ9A+pgCbPakPEkF\n6fCWUQqh+e6+VdcEtxHhFFPzSpjp+CYhf7H8lCKPs9pe7yfZXO5F7fxFXRwf\nnnYj\r\n=WB2L\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC+B1k+ILoz4j8VfPE4NkZYoMC0cPgFgi1cbu5/koEDFQIhAJGS9mnLM/JLwCSbyrzIQafUZHDLnzKQYhPPX1NtJp/3"}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.2_1601369905288_0.9383644478908213"},"_hasShrinkwrap":false},"9.9.3":{"name":"micro-kit-atlas","version":"9.9.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.3","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.6.3","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.4","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.5","@types/sinon-chai":"^3.2.4","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.0.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^4.0.2","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.15","tslint-config-standard":"^9.0.0","typescript":"^3.9.7","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.746.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.25.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^7.8.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.0.1","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"e66e07d5845b6031e001fe1630eaa4b69db0d7ce","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.3","_nodeVersion":"12.18.4","_npmVersion":"6.14.6","dist":{"integrity":"sha512-ftYhEvpBVypW8slX5uW4J3qdizqfl/iFjvMFyrVqenpf+11cLJMK3OC6vUl9lQdhZM0kspRgB+qSVJRXDXiYKQ==","shasum":"1d29842ec9f8da7fdb113f8dd3db57012366e287","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.3.tgz","fileCount":159,"unpackedSize":527288,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfdFHqCRA9TVsSAnZWagAAY+cP/R2XwHcTobGIsuo6uW0d\nJvR4AsJyXiJQXBDyRL4K0rmASO2q6zEbmUZxQdXJg3qmf/stm3QT8/NbqWBC\n2MAIcV4eKgE6lyIHHC7KU3rxLtSf5nmmkOwAixZ+llgt/0MEQVd/NVGOAAxg\nUPV6PKUHE19YqJhASHr8ZwTzh3rxT5UuFlEeqV6fo2l+YQasZMZpJmwR6OU4\nBQOuYje3Xqz779SpSIi7d8DxAZ8q5vJRQBihu0nC33x02CoDTK7GKJwa4TNi\nzcOC6r1Mv25diLpWlfAzggVHTPgteZGMSslsTfWPZTX3u64Mx904gwEQr0Vw\nC5VLB1/8MpHaRQsKtzrXyK7kxHVBWGEAWkb4L2r2wGluoqJGHn3K9iY7wksE\nJ8NtrT6pNBeu8oQ7I8zEHalfAASzuLILVGlJ9Utc/xPidpVAN/SGj5QSJsRA\nh451chTJdGRVVSA5GjJIH0NHAZQzQXOdhBZM8QlCzsPThKLGX0uhCFlw/+lE\nxcIVD+6062D5irNx6wS6Qc9QarnPdNExtc4E501YPRwdwQYb65VP8T3GmrJL\nMh7SCadRSN2TWCUUjBkGzLcE07HUYnTMchIEvLj8cXmTyCLZMj2yF8Wu5cko\n7/RVB92P4yZMbqvw9TT7LMcmloNG9JX7evtTTTFxc96tBGpM/JOyGYvBBovK\nstrt\r\n=BXxG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDcOrM3tKCR1y5eTC3QfrtJFKn5fWEqnnShEjZJbEsazAiEAmyXVcGEzcFoTzneDBYAOsMikLt856duBcjds79nP7C4="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.3_1601458665665_0.3754107096354653"},"_hasShrinkwrap":false},"9.9.4":{"name":"micro-kit-atlas","version":"9.9.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/cls-hooked":"^4.3.1","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","cls-hooked":"^4.2.2","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.1.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"35980948de14dff708d6c578eaa833046bd1aae5","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.4","_nodeVersion":"12.18.4","_npmVersion":"6.14.6","dist":{"integrity":"sha512-kj8X3k6OKhFjTSNEIu/Cx+cFUqjE8LIVw/28PIZX6uLhzdcebaGh3SfPFErPUqi8+CZo6VYfN81Jw8Vbnkesvw==","shasum":"81dde10bcbfde8acacbb47f5c7eb7a04a3d617cc","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.4.tgz","fileCount":159,"unpackedSize":531075,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfdkj1CRA9TVsSAnZWagAAdrcP/25NZDYpKLB3X7RZOfx3\ndTe/nmeWBcvkCNNwrS/jefqw5KIkd00Lo+xB7CDhxwimCvjXW3555kZptQhV\nX7LA5wadotXPjXLBD8Grx+Rl9WoiYWkcQGjXiiFEXMqP6KLnXgS3dmBy4R5Q\njcH5L2ODciBMLQovz2UcjRuft7eZPmhXUP4OP+9y7XSRKkQH3yoJLXg/iNWD\nqx0QH9RWGxmLMWkYYDq2eT/pfogubGKlgNZkzN2zf5FR2Pjm1xyVEHg2IK15\nD1I0nH0hEw6NN6a1T2vE3Nk+KfInpPBU4RJ/T/FDBrLqz/oQe7hkrf03lGIQ\nTHm1IlcDyiZpX8kuwOPz8aoo2OTR+icxq3Y78PB/TSKXHKraFgz2ycr0/N0V\nDXF/IlaMtNbKTnYWs951JfNIbF4JBQIpf96u0pvU2I/O1gFcXj238y671Jh/\n7sPqkjJsaLwqakhLn9N71X9ep8m7EkG0M72uA6Eq7oOIT/9ctsYKcj6y7bEf\nRlCwayUzfxlYxo0YSqapqDOdcQKWryPg5/enEMnqHD7+VxcW7L4L7qi7zM6F\nldBU8D6ncTxQLtJ0Mc48IPiU2c20gzkXsSf7Mptpa4YRHTLdDVJfN8XlJWGc\nmLT65PjcjN/3tLnz+i7W7Gc5Fplsw9Vdtn6xPZU5GHiT/AMRD4Q1Hvty7UAZ\npG3l\r\n=5pzB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDLMYH3lVMlzLeYSxHHu8kTWZ0el6ily8DMEuq+PoU4OAIgVCWOt9kPogyOS5SUNCOshPj2SGlMan9APrPBpuH4BhA="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.4_1601587445013_0.11060767354748369"},"_hasShrinkwrap":false},"9.9.5-alpha.1":{"name":"micro-kit-atlas","version":"9.9.5-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.1.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"13e09a6193d5add71015c836356fa7689b9c5274","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.5-alpha.1","_nodeVersion":"12.18.4","_npmVersion":"6.14.6","dist":{"integrity":"sha512-/54Dmv5YEb3fTn4+pLQgaAADxgu6tONNefwM2tj2w+bRoVyOwLv2cDR8nceiC93wXFlr/VP9nysV9qrQAEUl1Q==","shasum":"6009278d940534bace5b6933d5665eb7409f7842","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.5-alpha.1.tgz","fileCount":159,"unpackedSize":532581,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJffBiICRA9TVsSAnZWagAAJUsP/RD0xKoJvNJ8erdqKqAE\nWwZPpnCr9EMvXZupxAL55NEZbPriu91bvSuRDPt/z73DkoRUluYNeTwyCAK+\nd/uRV1BtEWsP59Hz9fq6sk7eYkh+uUZw/IIhxoc9k6OJE6/V3sY8fo09lnah\nySx0ibWxYDft9mhj001uAKAQcvr2V5wsYoT0MYSH/UJFynNTh5qxLuei1mNw\nN+U9P0PVhlB8Vssm/AOaAE/ghl9hkCIPcdJ+Qj67ILr5acG9rmMdk697s6Ak\npxhaOwW9no04jhIN9YRKIZP9NY1LsJ88uBRCo0/URkE6IGyu063E2wlitiaf\neoGc/ebQqXRcK4MI/t7ncUCP7MVSWoebCNEjMMFlU50s31FBN4ofz/O6RAVP\n8Y4tNkbjGyQcDM7DuNyaxJm+r+8UvVRYC6qey4cEkyx2y9E/fk0AW8NTS0V0\nO4xtJXVBi1XfMDUaBVMNgpHWBtaTh8js+v1XXFR1LqaHGcE1RwWmoHW1vFsg\nrriAuWw6+2GTwGThDPda9EVZWXDk9SmvNOrkeiXTOWLe9V8p2R8Ft+6kBnWe\n9ZZhWMMO+CxCf6pMtosmko8dWs5MRmcZ9j2h94fXdoVfmJrr8+PptNPvYG5U\nRMhNIIUlrICTQIcLwx0fEA2fTHfJRgg/oGVKVKLt2hFLWZbElQtdGt53LG7H\nMPpJ\r\n=PTlX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFVkcEqukQU7g7GBzFbZ3fymtfYeDqS9GqO/3bFlKzZ5AiBP7VQLGpnicj57uZlZW04ow2Bdw6E+Gu3UcQbH/TTy7A=="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.5-alpha.1_1601968263580_0.45104948451009386"},"_hasShrinkwrap":false},"9.9.5":{"name":"micro-kit-atlas","version":"9.9.5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.1.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"13e09a6193d5add71015c836356fa7689b9c5274","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.5","_nodeVersion":"12.18.4","_npmVersion":"6.14.6","dist":{"integrity":"sha512-OJF7a/8tyzqU08/hbz31gfh583L2nAxFrtaQ8l66EqNSnQ9a6mkHDLE6r6VshJdq29AW1dJMbwbZFdoWw/DY3Q==","shasum":"27cbb0cdd699aeec80bc3d4871ce17a971ae0d9b","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.5.tgz","fileCount":159,"unpackedSize":532573,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJffDOpCRA9TVsSAnZWagAAWm0P/icedveDaAPKHesSAMnl\nyHLDtQgtUvJIpQJiiyI+ttZBLV8zD+ypYE4LUgoZE6vJtk+JHehH75TS1Uj0\nI+eu/HXyHCkUSrPbdxev/7Inwusp4SbE/YyGdNUuxfo7GliOlh6WWn8++Jt+\n43zRzqACmzJIdZntDb69lHY3y+G53X4tLTH5xASgojUMk7JFjVZ6/Vdq3AMF\nja+WdP1aptQfgHvEWBs1YW80ZaNSYfnfWMTBuHETSeujOtkHfBdKFB6gQ4e9\n2Xls1Sz1TFm3U2mqLtL+cI7bm3OVNOQ0I3DCj4AviQd6vfj/LuYD7rRmGwpI\nHEda00j5XFKhj3+gRjfv9F+NpxmxPOez9oT2wpWb260m/LJYBX2U8L5Jfzxd\n93x72tkjaFD/nwf0zpQj4e9YJmaLu1fh2T5piO28kRV9L0hMoC6gM82LtY0R\nqZ4s1qkOmJw7SeM0VBc9Y/ZfMdHgUZwXl29TTU37r4w9SL40bABd/zjw+ZPh\nrU5b8xQCyL9bdL5M1AaPf3Hd/voZzliRp81+DPKSqTF1aXa/K8Vtb+MtNwzp\n1Ek6wk+/TqwQtiL2VsKAH4eTWRZP8aWDr031/gZ37fyVi2Oir/bb/6I4SOQt\nWsLJLZwHZIIkhv1ep93Uhk15q7qyU8hYrj0lbGaZQ+qZV3SR7gC039bqLmTW\n6h1M\r\n=BeSg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDQ+xML9pBNrqcEG5L+UiynYlCGgLFm6rkFPr/bAlWn7gIgJKU0f0tFNmlY5eqIooLWQqPzPO4+cejiJve6CFJDINw="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.5_1601975208353_0.3477075889195895"},"_hasShrinkwrap":false},"9.9.6-alpha.1":{"name":"micro-kit-atlas","version":"9.9.6-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.1.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"e6f58352c4197f2cc538284e0f4c7082614b15cc","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.6-alpha.1","_nodeVersion":"12.18.4","_npmVersion":"6.14.6","dist":{"integrity":"sha512-kjzl7vytsCr78Cvq1tPWb/1+rpmqwTB10jnWq5TfuzZUqdfgh8CuStbDaTXL6ATZfBG7xLDkbUXjqsB/NkCUZw==","shasum":"c76e6ffc0b1036bc5c6c6ad454802da2095c19d0","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.6-alpha.1.tgz","fileCount":159,"unpackedSize":534484,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJffDUeCRA9TVsSAnZWagAAy+4QAKCYoZdUUW+F4InXRllv\n32+kj6VCjTavVl/KBvLuhp767vNd+EfQbex0eEYpk0LmW/n7UueqwZZ2ro0/\nvVKcwqkkguT353nJwqrqIEcfwsXjMj2Ik73ljRG3cNYgoY9QOzpAJowT3UqH\nj2o6xukVhlp7D3J9xendL6CxdqNolQMlCr94gLkVrBhKfI9OQF0yK6W19mNq\nYy/M+Fhbip2flJsQS7nsots0g9r7NlqkPt9OQX243IgTMNWsj8tgIVGatB5U\n5/DzGc8zZ/uUPGwqg9njHmHJtCRPDw4fNGWVUvBaa1hQDWcsMl+JS1tk14rG\nxgRNaVJ/Iwuf+jtCy1nmHJCVZKwJ/9YMHQ/0v5yszeLsgkYlSNutja/+ebQ/\nfbIJU8hVVl8PqACRi9NzndUh+ZiyGCs1ypOc9rHvnIGQ5pp9LE6XSbNSqCYN\nfwiFNHlHci1LP0CXynphFbAXitIUBQHRU1ZST8IfSq5OStw26tvmAoju9Hkk\nNh4EeQEfYbUxb50PLaJ+KNTKawfDMxbt+86NAXoEMgJGdYci5FuHAPz41BkN\nf5b0CAfjayusP4BNZtM/DbJV59fAn/MRT5IPmo/+OP6dCiK/Q0dvEfVz+QCW\nS/JS5ask9Zh9K3reW3WwJzW5BPb5YcqaJlzz2RA7GYaXjpC2r8ln4nSr0pTU\ncbIn\r\n=a0YK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCT2jA8fVuPpI02q567btmicIJuRhYxWPk+jgJq6ObsIgIgYzzNDJb+P+j2CZmJeWq7sImu2EpXs478KE+kC63hUH8="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.6-alpha.1_1601975581746_0.2521719215020546"},"_hasShrinkwrap":false},"9.9.6":{"name":"micro-kit-atlas","version":"9.9.6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --require source-map-support/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --require source-map-support/register --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.1.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"6726d76f2f311e519291f914fcee94f4381f697b","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.6","_nodeVersion":"12.18.4","_npmVersion":"6.14.6","dist":{"integrity":"sha512-96oMZShAkncuzIfNYwrcSWIH3C4Ppm1TW+FrmTCgwZMTcWJLXg0KDPSL6TPQWIZ8WaC6uTjgeLVtUhbO9eB8OA==","shasum":"d806b176b5fb04ce464e322d6938b951206cb828","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.6.tgz","fileCount":159,"unpackedSize":534476,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJffEe6CRA9TVsSAnZWagAAi0YP/3f9ca/qWWo1I/HG7ezt\nWZj5pB2WNfSQhnjpwCeO6YhPOajWd15aj8pbhJGPdCmCZJ/t2/joKY+ErLyf\nkZM0IN/g+Lwh5iEllmx2y1SGBYDw8PIuy9+tc32GfpkY2kaLYWrCu0c1E3FX\nVc/IXLPeeFRkEJD8YzNhY752UtPZkp8+fPLniFvf853DNVBRk7fKyh2wDs6n\nOTV+FqBzX6fTRCX3SeyOXucgFrGlzkV2w8QSTpB32BU0qKFFn+TqXeCzzHFr\nZW87pAwFsqP7XYjW6GcPq1GLmjhDe1ezEhL4sPxKQn3IZ1Kn2M6hLF10S5GF\nSBhUJEA2JHAn4PEt0xcuisUGm9/05LVs6fgjUcHPxAuKuTT1z/TYHs51W8CC\njH/+MT7zoWB4npJ8l3EqfH/66ytpnZNPBFSuXHjmi7XtHol/xe6qzCE3dJ11\nw8zSxaiFqr37xhUQ+oxf+IoCGm2AnwVAk6hTfTEPo39lYxhNQ1ZucEOvsHTE\nspkhDlmyCgNCswWEaSzP6pieOYyKeHISPaFeC9acYX0RaWd7QacGPb14HAai\nHWgUAjzC54PRSfRaPBHS/Rjr8HkAVSBCKNuLTMAX50nl3ysCH1VBnGtgOGqS\nqLttE81x1pDandLYKv/9tFSNcKvZhRDVuMQl4rge9SlnSXq9S4niKbyHps4q\nQ752\r\n=YmOx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIH1XVcw6rBPBwcOcuwYK+2ZlV9qRjKtTyf4HJ6+DN/H9AiEAydAAtHpxiyUjibZI7PESZCeWqMr+UY+5HuZvIOxUUh0="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.6_1601980345480_0.7984237224033113"},"_hasShrinkwrap":false},"9.9.7-alpha.1":{"name":"micro-kit-atlas","version":"9.9.7-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.1.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"8714443416133c6db0ca194e63061fd11dea174e","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.7-alpha.1","_nodeVersion":"12.18.4","_npmVersion":"6.14.6","dist":{"integrity":"sha512-ik/lnRgjYGwYUresJsKtW1sygxC2rTbtxSt/2578N1fMQ4sd0zqJSyXNlO+8HB7U20GOzcbGosd7wW3wqQyBkw==","shasum":"9fe1488ca59dc2c17985c1c059fade32f12e3816","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.7-alpha.1.tgz","fileCount":159,"unpackedSize":535885,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfftHYCRA9TVsSAnZWagAA/JIP/R25El+YobaDe0kzrEc/\n1vTAwvmVPwFyFNLFLoWaN5YmX1wWh6nEGftu7MMaGW2iCyl/K8uElJa/StmS\nDLbuzTfMyS6v0bmEBmibxY0T+VgKu1Vy9VJA9a669Fn4YcHvpfnaoskDySIU\nfHLDPtgI5dC00BprLJeD0a1i/sswQH80xfgFQTMt/WFHkMBXo/ZNhJhwpyan\nDJgmE9SSq2cyDsIoFWsUUGaVYpypX7GwyQIWhMnHxQ54+GzQuAMihQ7KZVOB\nrHIoCfg8JbazvlaBaFgxgNbQ4o6XMgBP9LI5ZIgUutur4gFOA8T1TkhwARDA\nk8MEXiOj7ezfw70AgIpLL7tHt2dmKJj8QRGP/ssWkvCWhSbL7ReLe7YRYg1r\n0HY5EzikLRE4liUpfFa4gNJWHss8Bt0Ay7/Z49J3aubgu1tBOjSbTKRfzEJf\nK/Gihnhaa7hecRHO9Cws2bp0w6e3cC8bsJRkMEgHcO/ikq4IsnKgIU86E5Id\nwwcATCmOTsy4oNJU+7ktBy3yoDHAQ2wUEhx2lGAavXF3HDAW64Xu2JNhe+mh\nrEPvpt/j2OGKJXAfXfquyJluEp4UNIESn5F65C1zP/jWbicGYFzb/fZ/F+Ci\nRSzqMpb9BAXDfqeNO51ZXFt8wXKAv9ERCF9XLDZofHIlzojSVgxXGy/MJB1b\ndEvK\r\n=ct5a\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGv/IVGlxTM9RN7ktzVQkcLFXUbGhdQVdvYDp//ar39cAiB2+nYoCJS96O7lHJ1YHrHjeXGu8PGovKGrzuNPxvHGQQ=="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.7-alpha.1_1602146775463_0.9521706094231728"},"_hasShrinkwrap":false},"9.9.7":{"name":"micro-kit-atlas","version":"9.9.7","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.1.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"738f8cdfad03b1ce92d4510eda0912a7c5f1ba1b","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.7","_nodeVersion":"12.18.4","_npmVersion":"6.14.6","dist":{"integrity":"sha512-2O2Zn1akoAmD8er+3Bj7S01izqBttKJIoZCZxw0DNSCy7RLOIihubbQXitHyKV4OrXZqTYT8MiCzJwFuZbx6LA==","shasum":"be97a3e0cf67f9f971d74a3a7cc723be2ad24b12","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.7.tgz","fileCount":159,"unpackedSize":535877,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJffwjICRA9TVsSAnZWagAA+zEP/30AH81/3YUwvU9cEA8G\nO/zQsQneCF6fy3U04wY0Y3wcW31Aq9XBmiV8fBkV8koGTF6jKRz8oOsq3o4Q\nrcY6Mr2JJKcdCQePD4QIlz68o0XCQxDOjO57obKw1Tl8MYhYpJoHYagV72t0\nymI1+ArLWTi8buUGMX2kXXzwC5LFULlPnySV8eecYaI54cHIT9NpB2vFBdys\nJZluM0XirAyAjuyclREzaSDAOiBYpM5tyjDOCFIPw7plLF+FYp79YRLxjwrx\nCSBhMhMldR7ShE7b4dB7TPA6jEPB3VuHXhvBtPAB7LW8FI8QXoGpgsfVT0FZ\nCe5vwOLmgIzN846ZxkmyMbyJfVlTeDebTKARQCeC59/hxHahVVlFz2xLka2q\nhk6rrRY5h22Z5UmZZf2czRC4aYNWrTrV11sBPv27grrPrzNjsvPF/tICdYif\nirUfGaoawDOspC/Bfhpsj2aX+5DtWL6Cr12suoIHEX2uLNuQrhWtSG8q9etV\nE+LZqkAnF7K4l7VIboZlUD+jGihzKxt2fkgT9fqFNgpV5zeFlRfOr7hDiDDx\nRFydcjWwxxr1DRLMwwWJmXx6tXYdNMzKcmoCHVWYmzg8igWNGHbtLlfL+gFA\nuwdk1JJeyQPTXjmCRag8ecD6dLVO5+c2kLiPStG9J2b6Jc+avWfT2X8MVgV9\njxsX\r\n=OYET\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBx/cUBB1YSrK1SG0Dtt1mhSBX+HXQdgUlIOhFlDE66fAiEA2FhcLzGGkQuKra6pIuZV2BVCmhengcPMkchDZkTWoqw="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.7_1602160839625_0.22498550025192876"},"_hasShrinkwrap":false},"9.9.8-alpha.1":{"name":"micro-kit-atlas","version":"9.9.8-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dd-trace":"^0.9.0","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.1.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"4bf4c2a6a5717c3dbf2d3a3b5f6ec921edfe9a7e","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.8-alpha.1","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-xf1DdoACTpbZpNK7msOTluzhfbalnSyValhvTgEhXD1VFGyh6XJOgiFVAGEHeh07jH+LDSduMOa68ckilL3YoA==","shasum":"0b061b82ff9aef14d49c93edd666e9ad1c587c8e","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.8-alpha.1.tgz","fileCount":159,"unpackedSize":536170,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfgByLCRA9TVsSAnZWagAAqZQP/2srdF/V6P7WEwWp6TEk\ndMlpB/3b1cyEuVkQxMZ4xE8v6T1GCVgu9e/CtztRDo4bhCd0y/jJ7GkI0TnT\ngwalOsHgFj9VY7iX2vLjd7NPNOOMWIcG952RSmc/do2XPO4MxcpuT1V6RHAP\nSJkicw4FHp1dolWBlAKfvGgQkFeAeDrgkYIf1c28N5k7qYwEswiG1Ch0g9b6\nSyUATa3pvHrbqsgemPN+PFbqwcBpFWxLPWf8UgDhLSC15DyMXvtMk69tX7mj\nR4fjcY8OzHEp9Ba0iDxQqtAaTBoqEgeHpqPW4Kl1yiR/bKEzYOsFg474MrMg\nHvRvzlstuW3ZgEUp8xA9Y1EZ92S/N8Ja8ytHCVqKwD90ygWmt7S9jEck98wg\nteNX9NBBHVWVVvcxin/7M2eSvC53BW3Ll1mYOoyi4KwJJsMQXRKw3YDGa8S6\n3Q3ElrJJUTtYZ3ZFVOCPwSlqBi4GFTrSUHwevAc3SkAAZQ9/047OMPLd52G8\nJC+rpR+FGgFY8W7kKkt2CKdUhsepXATgHET+xyu5RLFag84PDSyQTD3HzQFb\nk1oOrLWp9+vcZFyFVyUw5qrMPRD9MHgfjm51WRGirabmJ2dhq4a0hmME81o3\ntkEPpy3g2aOIcuJ8oaZnc/DVh1ixT98VIpzB8gMFT5LPmwVNIdk1TBJ53pQc\nFHmL\r\n=dWbi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDMpC0yLpGuGlUraC/JFpeEmVGAObvXoJmpi7N9XUyT+AIhAO2q6KrpeWwUEuzzp7r5vU+NyZ+PRwCrrU5MzG9HokZA"}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.8-alpha.1_1602231434875_0.8519087558386327"},"_hasShrinkwrap":false},"9.9.8-alpha.2":{"name":"micro-kit-atlas","version":"9.9.8-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"eb23d49cf6bba4d97841c65baae2b6f730258cf1","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.8-alpha.2","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-OcIMxXLikbTmEwuF7KwjjLed84iLv2mSuFE1Yp/A78QAUlM9ZL5S0RHV7lo2wT/s5YPSGzfDZGy/GVIRcfD2CQ==","shasum":"4a06473c4aadc30bbc40c59c1246d0ba4570acc0","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.8-alpha.2.tgz","fileCount":159,"unpackedSize":533764,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfh23xCRA9TVsSAnZWagAAXFYP/A2yKaoRPfvDg0RhbYjS\niHs8QZYizOFv9mv8i/Mocra3Ytlh2CBOGgqw+ZxNKLLSs5T2ZPmDZWBAutUe\nbtGMmSA0TkTPeYoKXnDmyo3PcUwTcT7MDVe4EOXKDNF8FFk9jZtV0g4yc9PU\nG7POy2U1l7MBlLcXQSOuXsUCTnLmwgV1B3zNHATBFn2IskAyXexrJ5FD4CcY\n+3rjgtpAv8YrddRkDywsZ7iBUIN1eJJ1/6UoXlhGwDiSyt0vfSZTYroOQoiF\nXCHr3iTBHzzuFBfL2r7oGf8/LjplVepVsHDdXIDDXCsWKfYFN5RWBg8biwTM\nwBXdQMI9fXRR4crVzGorPBr8hNl+Zk+pVMosvIgu0df20SUWN90fVpOOMOyW\nAbpZ4bxx2Hxdxjb0QG30Vd8rm0mesUc8AKP8CYB4MndNZ3xVhJcjcMsR/zwA\nCvN3GAwqLMGO7M52jmBk5k9D66OxsOZY25J4zcO7Aq3tc/Bjie/HxUUIrwMb\nlulM01Gs9yuLKkXRH5+/U5vgrK4fbON4P6SkmHaGu/OS+LM4tfYXjtepuaaA\nnI7QkX5DzoD0C61p1YaYkgHR7Q02hhZvPYxdGCNM6uvCppetxXZ9kaFRpv3L\nKUeQRvAhcRaxAfRF5O3HnPClc1FpHlOoV0PRKoYLroVj8uc8l1vbg1Ajp+Sk\nFl1T\r\n=M993\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCnFKddQMHVIVbnVFp/1SZ5RRCaYT4rvXdFsTZg5wkLywIhAK2oFZDPi35HqgJGbal7FklyF4rL+CNFBVoZmXK7ldT9"}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.8-alpha.2_1602711024963_0.030144857803555247"},"_hasShrinkwrap":false},"9.9.8-alpha.3":{"name":"micro-kit-atlas","version":"9.9.8-alpha.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"cfeb27f0cae7a70f4b5e620628e7688c9460d651","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\nisStringOrNumber (value: string | number): boolean\nisStringOrNull (value: string | null): boolean\nisNumberOrNull (value: number | null): boolean\nisBooleanOrNull (value: boolean | null): boolean\nisUuid (value: string): boolean\n```\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.8-alpha.3","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-gpbYwdfuu31m+4+oMgpMCETyWTk8FikHPeeNS9KIPyBRadTd6u+Muz63W0zT31P1NVPuQXzhEqiQk1okPGo/jQ==","shasum":"4fdb5629e6668c8fca952c4b05633b0ab1894d99","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.8-alpha.3.tgz","fileCount":159,"unpackedSize":534688,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfiBmzCRA9TVsSAnZWagAAA6EP/RzsGCKs51ToLn4Fc8uN\nr8Do8ubfU8zM6ykOlfNoH9AlwxFSRMnDkqQPDdQDjwQ0MsnP5/mD57sLdSbt\n64iC8ejmqr0AGAFqAwKeNieTUPmIyKQHHny6tyB0dWLjs6XwiRYGE9u+nPqD\niTY9Rv/cylNEnu+SVzPjw1D4QEdK1TszDdxWkYLszVeZ7gKvpm05EarwWbYo\nBscNimNxGd9SNY638Yha4+jhQUb7JHrNWmPmHKDF9j11W8kfu13AS8izXSVK\nxh9qEjp7Ci0ZxqXV67+DSRUl71ecdpNiBe8XwFmmEakskt/ycDsz2qL1uwDV\nSfURJildbrFtyHUrN4jQamMMCFXE2YQjyHTiuOj1F4gLBsrSlo8oPdejr3+D\nUkMjPjLxR1lcteiwfkUnGSJxZmlMbnQdKp2V06bHLecrFQes6fsIT5rP6fO4\n6TZ+oV6JVFQTx3FHudLhIhA62U+k5jdsl0JqJ4MHZ21mJcrz0kfcJVBQNAoU\ntb9iCF7fPig9i41VOea5WDuj+tzHyqcqJWeFFmP7TF1gwuSpkwVhYC1Sv2yc\ndAyfv89mMS2lLcR/wx8WzG1I2Kr0m9gz4KaoJNdsNOHYAHHwEgI/vIkaukzG\nr9QXf5pWIrdSvYtoX0ISKjK7m67+0wC5kb86/z9t5sp/+ZvYC6vT/w/MhAVu\n9MdK\r\n=zYrh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFRHZ5wzXM5tgdmufy/4seUP6elz3i0gba0HnHCqsxiiAiB8+0is7AcIrHtNu6KWjO/eEZO7Eg1r/SKrXInjnvCGXw=="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.8-alpha.3_1602754994560_0.2628863445561376"},"_hasShrinkwrap":false},"9.9.8-alpha.4":{"name":"micro-kit-atlas","version":"9.9.8-alpha.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"e5f4c16f75bf44dd8f0e7affd4e88a7e755238e9","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.8-alpha.4","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-X6Bsb8VF7PUimxxZK0VHo3CfMbyyt6f8vPlWGo8+qecTbV/Tb/6L1CVL1IuxKk85DqsYFbjEEEFNoD0y3H/mVg==","shasum":"fbc32710da31894c6ee24bc38eae6036bc1d20af","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.8-alpha.4.tgz","fileCount":159,"unpackedSize":539576,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfjUlXCRA9TVsSAnZWagAA32kP/itbxDx50A+UrRgg3PsJ\nA4dOc0w6ulZb6GHcncFoSVwmID+SPPRcKIVYpUm/nWISs2cUSp3rQ76YwIS3\nAhDoXlcNJYklCyD4QyQXRPjDFwt0l3iAOKwpFzmS6QxcF2feVPKa4aGteeq4\nDrp4cFJeIuV98/DcvTK9UzH90GAo3D7lMz5wj/tF5JSrJqT/pW55lvFPsHIW\nBrvlEnvKSfpF64keWHiZ5yPt4pZVEOyc8laqFhW28HBGdrxcwBUy2d47m5H9\n95P+u0PvYoTgqih342sET2Y7XdtzUX0E5eiLBPHVHXam0odFWskHa2zhW4RE\njhltLce64vDQSoZaOjHuEAEOk/aSnYJ80uyoYmUvRKjKHx2X7U4avpj436et\n/2oTgUT3XFs8PjT+hSPHteLaGw+uuJy/+CGSlOTponAitwe0aauKWVk/9gPZ\nq2b/6TW+DILv9JV9/sEx6bfOKn8grisdZUzyawMOPyquo21sC7BtQmPvAdGX\nBJrU+7FlRymiRiC/+X/Tdu3SvI4/PbchaHNrU6SsNJWEzaHf6yoeJJAgDJ4C\nzPg6W33XbicR9SksfaFCiDp+b+pjNDBq+MdQfDmdoTJlRlhnMnmISJ2V+36s\nIpgDI8Vceer1y3/qupNxyAGk3L1DLLyecEQ/xotAVaaRkXv1/2iVI3e/IDaJ\n8ySn\r\n=aZDb\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDGwn/wyN/ETXb/Hv61Y1ib07NgquA3OdkQlMcUgC4ohAiAZNCfWQti2X2MClAwS+9wO+3tW27O2nNr63HAJBtmssA=="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.8-alpha.4_1603094871132_0.810426291562095"},"_hasShrinkwrap":false},"9.9.8":{"name":"micro-kit-atlas","version":"9.9.8","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"5a76fa47d1b57befad0afbbb6026f2cca32d2640","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.8","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-RqG5I5Cu0aG/NhoLIBgral50lmgcVEE6DP9mZ+kWyBJpvLDGxcbxhsqkLZraS+gE75pqubbTef/ljjQjdgSYkg==","shasum":"e376d7dce6915a1084291d6ae096862e6e1711eb","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.8.tgz","fileCount":159,"unpackedSize":539568,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfjZTLCRA9TVsSAnZWagAAFVsQAJXgO4v6fsAF+aezI7TK\nlweDaoN6rLf2ZDjHp2ilI6nDeghhkZCpXo6/4jbrdOoUf1B0iN/y70XpY61t\nhs345Bn/FGQfR75s83GF09Zn9slroeTrOOyihW18ifkLjs7ZWfnjoXwb522w\n16mfSPoIimjt98NRjo0bnaMOoAzWbS8m1dPHSwSBGGFfKAN1ZjVR0wKwSswk\nLNVFCDIy75HXmCYmYJ3jgTqNuo3pxd6Kx/W0/5eRwWZn5JYVXI0/mXw5I65V\nLNI+yedacDA5pQ0niiYQirUexlT/5cMk7hDatGzrDQadJoNA6rRfxNUQnF+4\nUBGmgOR4fo6GfloUADaa/YCI1Fld0Or7vmTgXgs86sHYQpzK7PuDN8+ZkmWg\n3Lad9x7yU6/HfbC+W6gBpjrVpWKcF+CrNL9QGUACsKUqQsj2CvPtfXrZOZY0\nEcEyJKqvbPEMUqJl/oH0SiY2fxyNK/6+2OJPityoMuQIc5APefwOijSSJErM\neWd2c1lHT3BhWZl3dugxrYS5N35jYDika7D25igSdLA8BrZl5vUP0BQ3PXvm\nGYg4EhgEyHmpoB4T4q1eczzXUXai+UfQ5p0buw3iEqCSkZ9MPt8sWaaZH5ot\nrmQhV7+eWpzfzl3fllVK8vkjqVA/lz7EecvlyJOsokOab7PoWtnjxl9GFF6Q\n7q3h\r\n=nE5W\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID50wFavQ24JMcmUdFQCSLDvs5ex68H9WfkqKxINOY3YAiEA1vgtScPHM8Eoctn9P6rCflv7R/bB0Xlq4lz6H4SDwj8="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.8_1603114187081_0.5983712201730127"},"_hasShrinkwrap":false},"9.9.9-alpha.2":{"name":"micro-kit-atlas","version":"9.9.9-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"d51d688f7f1da98930e8d5c2476f13d7048bd25e","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.9-alpha.2","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-VEYOqV451LEWnHfdOHJjQ4p8vyn/7/qMJyk49kEaGMh+bUfRsYi7MfRIwgAN1pCRMODk7tqX59Yj3xoTLGDHTg==","shasum":"05d9d8d069bda31ccf8fde64eee35c2a19a13303","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.9-alpha.2.tgz","fileCount":159,"unpackedSize":541528,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfkXNPCRA9TVsSAnZWagAAkd8P/A2mSy7Ka2CaM8e+1gnp\n+rMvDec9De+s00T5zbXCfpytozkI6BP/L6AqTHurnIB37moh6rdb63vFEhAJ\n6YDamTKM63c6Ti/ohKVCGTaIvMMYwD7VF9KRvbelP9tLF2IlwbC3u2Jr5WSA\nZUvvdkO968s1bhcI9LNiDdy8zwiItuNmYTeLLkSeuonQVcZtLJjVWkGqUx8i\nbTWrLWoyvNPkLCKb6LPwV4IJ+nh0TmtPuuZpwK6iDhld2rtHDgyl4jzufzlH\nYnVPIbgy0R8goI96hKFyyNh8akHWAz20/u+CaygnitaVB+i1rQotJXr7A6Tx\nvXoFMNG+4wqu4NXMtKjIJANTK1QZWY3T4+iWWXD4A44Gol+v5YXN+wiq8brU\nxbm9b0bTR3PoNd/kPKNXonOYLCbhmxyEgOJJZuFdeCinwYrFhX1rpbjB7eHi\nVnWpvoW/h7kkmQeQxA/fSqvWO8n6Q3AOpn9V4ghPWsppJ0CxsyyEtbsH4u1f\nJ8wIPHLnKEaEXsAStZsp/EdY9Xlxyz5a6ylU+yHir1D3UdDzF1s4LJaaOzpz\nqJkPc9/lXiDsfDprOgmoVRxX85HWXb/A4cuZW2sFRicjbiUqbpReQSMqcNvm\n1xTYQogXJsPcn1p6dd/PhPqnDjOMXnAfWln/PK2lpvd0XfGkNREm/ubgkBYd\nxz09\r\n=Qe6B\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBxRLrrmsW4tvFO4iUuADh0H8bvqCGMWiLXjW8YeZLkIAiEAsI4huXfSjWvNIo0aPyY3Mn7FGxdqa87p1u4XliX/AiI="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.9-alpha.2_1603367759300_0.9616128802491399"},"_hasShrinkwrap":false},"9.9.9-alpha.3":{"name":"micro-kit-atlas","version":"9.9.9-alpha.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"d8392cf48779eab2dcce2b2bf22aa6daa78dcd01","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.9-alpha.3","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-EAJ6SnB0h/IcHZoP4uqIcgvTv/9hOBsxA1d6a+zDU4NWZ+37sMWAwxcfnd80ZIGsaADXgaGFt68YCm5KzUFUyQ==","shasum":"497ad87612812b8dd36f956ce43ee88a1d097906","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.9-alpha.3.tgz","fileCount":159,"unpackedSize":542337,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfkoaUCRA9TVsSAnZWagAAzOYP/RRy8vjKRcqCmLEDwkjk\nKnNcN+u4H3C9ulYgALCLWOLs+JvqDRx+J5zdqgld3nmPYw49RLlFdNzlO9vR\nTDjkPNrnG5vJp0Y751CoBLTP0dejoQ7PST5LsVvwSN95fFVvJdGhYgmzt3Zb\nmvuINXvXIfGD6m83+ivV+7PMYyQcUExbqdAW48PdKoRPEV4JghPbvHX+ki1W\nEz5ESi+wetqQsCRtmZ187JrykdRqkIiLq8Htn+aiB5ajyk0LHcZG2CG0fF0O\n2ECRFipPg8gIi9DcLy8WFZ5MQlysnqNwwlcdE6mbpZzpCVtpkZIx/gaB5O5T\nfpJVYik16TCq4ic+Mjb70+1kwW9aD5taO6CyAlem7siRh1Ia92bNryuWom9L\nTtc8NtmJu+MbzG/u0aMGzwlj+XTM/KjE2nCfJspT9DyT5jippyWt/h2WaVjB\ndBwBOogx8osCvucGIZXfK3N7dM8iWLYmWTQZd22o1upcLTNM9miQEnjJc2aU\nvyebJ9azfYdHp2fLOnVE8/evOt4cNhVGZK3FbkxKcc4vw/u4YOq6zcYkueIj\nPIg3kZvrNYLTmG5V7OSAFu+3FqxUiFER2bK+qE/44VE13JgObU0hmZjgryrf\nC7jrUMo4BGuQ8/XgzG8H2NaWDbObI76MWWEIPVS4JHV1pWyqWu/rg2CdBuwA\nj5OS\r\n=b1ru\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDbIuvadO7fu1oPe+bJEdMx/U/TsIS0AOPJQFjdN39umAiBR4EKmb8KhpplwFPVtmP6nja0YF3di2rJDCKliifBLoA=="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.9-alpha.3_1603438227596_0.17575664592554863"},"_hasShrinkwrap":false},"9.9.9-alpha.4":{"name":"micro-kit-atlas","version":"9.9.9-alpha.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"d978c652657799f69b3b588a820f8c14c040d8f8","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.9-alpha.4","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-MlPT3PVPthewszy+JmJjgqvbVGhPRqLBrztkx2UUDxMWLvqvfEa1R0Lfe8gI+n7tbM+8y6+HjDx/g/Oqn8eWCg==","shasum":"b466bdf6dfa907414ab4dfd0f7892c77ad4e6072","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.9-alpha.4.tgz","fileCount":159,"unpackedSize":542797,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJflojBCRA9TVsSAnZWagAAqTcP/Rdwhr8WixeFA8i1JqC/\nAfETHTEJmkzrAw5VmU0tGSPlbcgOV6ierz3ZuNhPf/9OG4Bli6/tjpGHCuNF\n6GoiOxJlwT2HqzbwP4xR7BeI1mjITijbqzpR4c5cT39zqdiRWSgtGC+mj1fR\nnEltEmcUBodDddMYXdW/D44EhJL4I2WWPNYMX/oO0+JirQu84loGDuyIJ+aX\n7W3ww5ukowdvzl4fJylX+4udz6o3mwY2YyM3DxIVn9E51fb5R9BEPkN2f6Cm\nP/DhOY2Cmv2jrQztXBfwg7ia40XQlIWDHTQvKPOfoN/I2inUtCMKq9GuUXJS\nwpaEGjyCBAbfF1OBrJg3XzaO+GpYA3Qo2vWKvxXhfQyY+W+ZadVsLTaJSk4n\nuTCpWRJ12YuV6Nw/B6X/0uCk2YJgw7XarMNkTFmqUTyHVoh9KC8BejwrVPil\nmlUE+qf8zzi1T6IG2xGqCrTI+okMUwed3mUFs/+BXLrTKgm2VicF/BCACeLN\nLMJzdwjZhSphBIsCWgvIid4niKNmpTpqGuAKr7ddHtVCDjKpiddRD7uDFKbZ\nUro/m0y6s15R+klqSG2f2eRfeWPGf3kPWm3iyuStfwjZ03D/QKxXWiG9FrZf\nn/nEhR26kxnvBlIZcjflinFEqbv4SEYuRf/b60VdNEeBZlopddLNsm000SzC\nf8Aq\r\n=cZOi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEGR5BialBuSxxIIYIe8wzxdQNyTEKQNAkR3E4NFXoXbAiBCFL2pPLL/fLRXOAifW7uOIrrVLRvGNGacX/D5mzZWkg=="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.9-alpha.4_1603700928629_0.9062294444099774"},"_hasShrinkwrap":false},"9.9.9-alpha.5":{"name":"micro-kit-atlas","version":"9.9.9-alpha.5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"dc32d9ed362752d2af3c295ed49df77a6d21d55f","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.9-alpha.5","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-6W0HjRx1qM9SNLVZPirsWwCSPwF2k7tusVzO6bjzOMHZ+7wJC2extLkAVRtdgPCln/sCDxi015Ho9I1AdTinmw==","shasum":"a99bbebfbb96f4b8ba0031d815cc51ed269a832e","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.9-alpha.5.tgz","fileCount":162,"unpackedSize":543902,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJflpYgCRA9TVsSAnZWagAACcAP/34jd7PIDHQn2AW9JNdy\nV7ozXMeJV/gPHCyhiTF1LmgN7VpnmppRC0d49AMYviAyO65+wHsFehCCtogn\nLa3f5rsQmm6VqiLMfSma+xIj3B7a+zBkOCxWVogIpasB5s9Uq4wwCQHD77j4\nXpRPDEsrEcqRcqyVEpQbwcVam6J2jqhblZ+c7+/QmzT5uvp98Uet4+m7Lavz\njPHYFD5BJalDwHyrd7K4wzwKjmgOsGTtWWX+D8EpTlLmTU0AfjX2ctB72wbi\nUcHx05B7quwC7pYp4ZwmKo2iHv65h+HGtmxw9GMZ5UHEouDVPxnvP7JyHe24\nSsfkW/OsLpb1XAIR4zqqiyC92DDqHsVp2nyvgPbICCggEPdxRhuDmpNIzzg8\nvG8UIggmd4WGY4hd4XSHkhyXqRwMT5JliYHE1E5qfoFU8IZvIjhoyPCFjvwY\nzcmX7Chk7HfNQDzi7kPycmEHVPlObdxH8Q8XHAy2aZVymROZAncBEXbjednd\nAzus+9d+U4kkOkfpxszOdii7H6ZCikw5hgbup4Xy1WwWoC2Wie9AvdHyP4Qq\n1COxcB4UK1aKljvAMNekEVuFQH8lUDCfkNh6DGIJgM4HrAvUfsx4xQ2KxI5Q\n0boEountoRUa+KbK0F6PhEGS1gnayzXTjojfmxxKVyYvGNTEJHEle7fEokTp\nMoTg\r\n=x44U\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF2PGCDn8VfneDkE6ZIw4FwMDyxVOh24E+CoEJppaaDCAiEAqACqg2dzrwvdILmSicKPv8XtsSrCDN3NpWsXLVf9VhU="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.9-alpha.5_1603704351787_0.08689732254172755"},"_hasShrinkwrap":false},"9.9.9-alpha.6":{"name":"micro-kit-atlas","version":"9.9.9-alpha.6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"c322505125f6940b8bf6b7dbcf746e844feb948a","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.9-alpha.6","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-dLLWoDB5W0D16RzpvhCD32oZsKgUcorzS2/VtHUptc7ykYgWIKawWjZQKGLlXsd0S0/BOImYs6R1uGUEXY65lA==","shasum":"daf67012b400a79366d326e9a5b93661c574b20b","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.9-alpha.6.tgz","fileCount":162,"unpackedSize":543941,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJflsMYCRA9TVsSAnZWagAAiV8QAJ9ogcuhZ/0aYgY3Y3O/\nPLDzZ/mv/1oJ1LAAa7ZdAmNixzcL1MOpn7/c0Dw/hIbTFKn/VVX7C7jE8yfv\nob8r2ATPb6Lw3vFtOb+wI1M73EcqEkB2NHibEgNUu4qPqfcbQkEkqxZFIXLw\nxjDnXDOaBO/GI8bVOEOGnFIoTVyerTLca3vGCCN9EAx9eCVNgbkSsOd3zdgo\nlPDsPn+g1YmWrbsxhm2/EZWlAlAoCBPmFIia/HMoPgJdvd3pzY9fSQzzaBf/\nBPJl1wvon1D0f6p58V4ntoJcSrezr4F7AIrkxOiow1Du+v4iN6CYkAgVJ7Y0\nqexNku0vAfA+H3oUcFnMj/fXlORoK77JitOFGjkd2cVEidAx8rmvuyrneADJ\nmlC82DArVtww0lcX1XXknEsVnHgLUE/swmBe1Tz/qKDChm84wzOKbhFaNghU\nQqsrYyMMSjQKSNI4iPVY6KyMMzV0tVYv/8XMk/Rj3/eB/ilpzQhQtP0vvmED\nMBRyEIhsi/E2WsjeqzApde4r9qnb2xdsYu+D68qES4M6yms48FUAGffqB7vl\nf6yRwpbFHH1d926HEH42ks046ojnA5DKpzTsRFmuBRLK/oPg2490pyT4w9sf\nshcThCZSAAGS8FL82RTujY+o8sJj1+fnCTHjSvckC0OH3Ers05AlNfByVqsU\n33iv\r\n=SrXy\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGNG+nqXls28PgGpAHejXJT5L8map7o999dS7jZ6sYCgAiAPTX8u5FYSzdCjXIFZGM8T2dUVDEFfUf6lbz6gOQYxXw=="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.9-alpha.6_1603715864273_0.005643950489025995"},"_hasShrinkwrap":false},"9.9.9-alpha.7":{"name":"micro-kit-atlas","version":"9.9.9-alpha.7","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.12","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.4","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.161","@types/mocha":"^8.0.3","@types/node":"^14.11.2","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.7","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.2.3","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.1.3","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.1.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.763.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.26.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.17.3","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.0","winston":"^3.3.3"},"gitHead":"e2b392278b5ab3c5b93b08db363c642d69b3f41a","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.9-alpha.7","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-MoxA9c4x3b8kDc+JFbkPkPnFZMGVUKWVHbfBLpj3HAb+GuARD8M02RofIhrFSMKBfzaeZeuj3Jug4yiwDWXiew==","shasum":"ca37bea931574c03b262560333be8f5e839ad813","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.9-alpha.7.tgz","fileCount":162,"unpackedSize":543978,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJflt3NCRA9TVsSAnZWagAAs+YP/3x9ubdf/OZIHrmeWk/T\nZYlBaZGTOVUqXRzqg1wKo06Fc/LARfA8xYdsX2NeeOvy+yY4xFxgAAsLgRBD\nEiDOkNbAy55jk3Mvlz/vj35IiFcXx4BQrMbO12e5kzuTXtmQpHQ3vQfoIcx0\ngPYPcVZbZZBnlQAQzsSEIXZAd9ZwT396TSCgfcbEL7ML3q3KqcTC0Tmj0E8Y\nUi08TukcecicR+D3ml8hW/Nz1ksKBk1LZRb3bWjS8VSXQXW07PF7mTSwWqGy\nv2l8LWBFyYcmJRDWmxibn/4eKdHSvOOmwrhZaWcJytgei2eQESl8AxjCLnv7\nVoy6Cw/U+wi82H1Sk9sJUMntWF+WaBOzW/t/ln6Bi8WvvA1Ict9/C1gsWWui\nOHObgz2T2aBepjVF9ihMeyV/10GU0PTOdy8INMO/wugjJ8sbd76frB9cfLIx\nwO7KhUsNrJs8XsWeiJTKfKYMM76ySxoRcQBqU0RzsXGJY8l5Gu7Roj0wN8YY\npWNbL5kBwdp03lBo1nZTnzIRltwZBrmizVGz5ttkyP/1RDQW1tlIZE6EtARF\nrcCRqoPKS9AOazDcLun7ZbVM3NkYGi1kxcIcTwZ0rqXQps4cESNqSAbWA70z\nQoLnSF1Kf79wywd4tuKErghPpMmJICdqBGafTpy+KFIk4Ufk6ztENwhTPGOL\nLWaD\r\n=Q2hw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDCfM1qMBRGUMWs/Sfw6QJ45b4aCDZ9rBuPlGMmbB2gjAIhANf6wywbch4uKf9PbVBt+d3PktQjhGKlz7mOliMwTHsv"}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.9-alpha.7_1603722701225_0.5308998126437972"},"_hasShrinkwrap":false},"9.9.9-alpha.8":{"name":"micro-kit-atlas","version":"9.9.9-alpha.8","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"fb33ca40f6cbd81765b9a179a38e9d6109a1aaa3","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'class-validator'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.9-alpha.8","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-2/b+mcstQmrNoja12VPu3vklvo5wceEnpCAd/dTyCFrM5GpxHonnOFkDXtLUnagErdTBhdrrP9OkI5bNFo6hmw==","shasum":"05e01f7d635495e417d426d08e9ecfe18f70e514","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.9-alpha.8.tgz","fileCount":162,"unpackedSize":545322,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfmBYwCRA9TVsSAnZWagAArKoQAImDeYgPIfHDfwX2+P3F\nMetweZywgD+5Nq3TlxeSiN+PruLiMRjjh2jH6dXBHEGLSDnpL5eIQnQ3RCAO\nLzEZ5peX64PdqfwBWNVlWKLLpMSoUJZhhqZYyF+MPEkavvb4x6oLdhy5Gg3/\n2s9r0vsyE66E6SB/z77QuJRTsuEOcdVlhzaSJA7zgueFBMB7/rsG91alI+Rv\ngxR0encCJn+8dQ1BLuEiljHGgn4dp+wqSmZ9ROwN9GSzthVSfiRRaTFTeWSO\nqca3gzQxq3OvEeKrVKXKdGLYrHV2bTx8JVuxdBz/ghVDFlZkkgl0mTbIyfc/\nQjbtIzoEce+Ex0J44PWnBqnfXbNk+wJk8O+jzN/a6JCGPp3pSAyFIonsRPqu\nAl+vDUSsEjolGYl0LG9RA5X50DyLt2wI7NWxpZkqInc6mLdwTphAb+lpVMgs\ndI3fRFKDJ7oVqMZ5HqatR0lxyS990ZT0O0QVrcRehUdUuE284g4h5L4HfCfF\nze2k0UzLBfBr6LchVrVMdFaxZrWl2J2BfXYhCNUVX3MgbmpZYUbSmTX2yvPQ\nYPgQEH4Zh+rwFpaLK97/dUuRkt7/9AjZZ9aEdLbJZ44ek2/06aSHBn/+CT/Y\nnWujzW+z1A8vuENBwgB+RqYkWTHR+0IqQ4u5TUYAtzK/SlRGZAGn1UrjtT2O\nQkzy\r\n=eup3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGUaie3PGMUEb4R5pu0gJuzVt3Phzy/hCQKFuYCmdYo6AiA7//v3L6SOH7ujRwV75BA83r3l5F+pTd1d7xmL6lsOPw=="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.9-alpha.8_1603802671760_0.8779215573495478"},"_hasShrinkwrap":false},"9.9.9-alpha.9":{"name":"micro-kit-atlas","version":"9.9.9-alpha.9","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"11061a8aef2859377383d592cb52386e660f89b1","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.9-alpha.9","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-qa2LwbwPVR4ynOXyKxnPHGKywddu7BFzb13XBDpshbpTes0UtKtt/WMr2JVRhViuF+sqHegEfmej9itufPoJNw==","shasum":"fcd0547010b7be3d3c4283d56d89bee00fed1151","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.9-alpha.9.tgz","fileCount":162,"unpackedSize":546427,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfmoeYCRA9TVsSAnZWagAA9LIP/jUBPQDRlDbQALdmZ1ZB\nZRGq47oXHucT5A4HGPrYKLfMx2fn4Xtz68I7AkvXL/+7za+FtlBB30GfPRTR\nYBpcyuFYzIUBYbc7nmtuEi29kWwnGNbajaIo++ssDG0odW9zDPoj/B+uGs/b\nFCDkG3Xt78oPPVchvVjRHoXRhR6DJaZyqvVQhOIeYA+27AkViEZINzLkgaXB\npVru9LiPfK8eJ7t3EAeIdXs3ESXY9SeWaaW3bPmV4wRvOAfHOEH8vN5uWR0C\nGpU6VGEDljOcS59CCnRXKnUBK2d13Hztkz0pYhtQFwxsa1bcVAbaMEN7hTuA\nXQq/6KUIOQf+6n0s6Ft30LihuJMlHacbPcdNVsCi2KXMqErWXR+9hEWhuVcC\naZ0+eIk+MX0rZBvk32Kgz+6XfMO4ahtojgCnvtWRShUFdQrD3x4++oV6bo52\nGzJtH7WmvJnGXgEB0t2OVl++9S8lnmOBlCVMkiksV58v9llyZYHK6GoLD8WB\nDCnGpSuzsjw3TPcrbSCDtVbNGiogkFC43GBOpSlxlFP9doBo8L7XSEinkAb+\nPOR/+RPwPyuI5AnA8kCOjCBWWHUoxO6q/2ZrrZs2aERlPWAI85THmq3G+G8R\nkrDyC3dwXZrj6df/m+35Sg2m6wogLYHPGVmMTFmm53cEx18wLBLqcM2gUpcY\nbsZD\r\n=Vz5m\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHUuCQgAfuGp/uGA0IaL+a6h0YPAr45kMvsgpFYeAtYvAiBsiBIGkXBbGRe3jbp0mWviIThM+4AX72qmORPWt/mkWA=="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.9-alpha.9_1603962776143_0.47005785048958537"},"_hasShrinkwrap":false},"9.9.9-alpha.10":{"name":"micro-kit-atlas","version":"9.9.9-alpha.10","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"72d029d1d1474380b91c9d57f22f26af0097fff6","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.9-alpha.10","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-6WR5yFfhIKlKRmZD+pywyls66lzylNy29VvWoQjExXZQsVlELIoKZQxjATL2PAPWbH75d5HxuTDCrMJVQK+qwQ==","shasum":"dedd81b229c34ffdb381ac4caf1d1de5fcaab2db","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.9-alpha.10.tgz","fileCount":162,"unpackedSize":547328,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfmpZaCRA9TVsSAnZWagAAaEcP/iFq1XWRmsOVuhdLC6O2\nQSgYAjSI7qhJOnWPqUr59kW4vmY108Fh+mb7dOPspm7o/gwTMBrjDlxKAV2G\n5n8Ahm3ClNYNK3wW/3q5ImQaX/w1ANmlB0M5ScB3sd+MQrl0buy/dVx8ypi3\nVjST1TqK18uilA+Sg0sKND4Gw9ocqBYO5zE/gVPeihnlfr5FFmDTBm4td0z8\nTFMp2hOgR5dpBmBnzLI1oNqpYRkYjm7fReHe6IukfPfiCuJprBv7A+lXjnQq\nljb8xT2D9Mb8E6Wueu4qTldopF/N7sViL0PXwKMUb6qAzAbU8SNbMWQLiB0q\nD1QbxXAiPNMAN4CsWreT52vPtJQ9e9t8SP70iJMVAt5VT4lsyUXaPdlZZZyN\nzBRvyPex5y2zewxJsfvzBbBI3P8qArBNPlQ0zgY6MfKVaZkxW/BPZTgJ8vZZ\n2NedM8VexAg8WvfZzqzhC5FL4UhMQxaC+wMYqWdw582mH4+aam+KHFf37CEh\nGMjcHQyEzRc3hY8lOxancOzhn1LMT568fvfoNgyvhDTlFUsYP3xd8tDk+muo\naJdYUgbUGT/5Sp9MY3gsA4LzVmtSUY6rIHAvfqR0RyvVzgcUgzzixU4sknKG\n9aRg449A1Q2pAk/g+KJt1cOP5tDhSrZvvtMWaOGyO6PFRgY7tGjc51wQvSsC\n4sZM\r\n=uLI1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCLkplWrGM5bAGnB1Ah4l7ZQkYZfDZnW0V78wv+GBTc8AIgfByATpn6184OWPp4u6LkOUQii5cDqHy5gl70QiN/XfY="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.9-alpha.10_1603966553967_0.3191321647917922"},"_hasShrinkwrap":false},"9.9.9-alpha.11":{"name":"micro-kit-atlas","version":"9.9.9-alpha.11","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"e1fe0cdb967acb87b8329e0fa2ce55368f724c5a","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.9-alpha.11","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-bkoo1q+Q5GTdov2tGmpcbeyOEiBlgKHoOsqiMd/UVxtfgBBCPkn5GibvrFW/mHLS951RyWrqFFSJ581iZHxpcg==","shasum":"352c12cb9b913213cef3d25074d1ba7e226de996","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.9-alpha.11.tgz","fileCount":162,"unpackedSize":547350,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfmrnUCRA9TVsSAnZWagAAU/kQAIZ7osoPTFDu2kS2pt/d\nvODUHz7Ejlv/zK7ktAqrvSEf3OPknrexq0gija6Tw15x1U5YejtBiUDZ/0Rt\nTO8VzxR3GoVPRPuO8b9JOmP9O+W4GBaT3Dm4JlQ3uxdk2Hm3MMR9aZyioHHn\nK6VH2SD6rysBZLN4lMdU7F0xqwl9BteMdJIpvDaWHsABMtpiaBKjVxk1AEZL\nPjjR6Nizt3E8AEpP2MkzeWho3+SqJxGqcGW16JsEyDc/aVMgAEJ8d2TgIHa6\n7ThUM8WrKfhFrtpxr2VF4cSD1uLXkpUeIlCgJub3jj5+SV/vZ0TfWVXBz0Zj\ntMbIG1PGKah/C5oPEQ6OU0vDTv+NVZhcAkhlPpAlpKzTppy8yrDmxzgdwNVl\n47tvKUTTp/n6vrNrly+sWUVAAsnQkOMcfQwdTWSvdinpsefnbH5X+OjyYRCR\nSzvZ25J/9mLgHL0GLXQtoN/LDqDtbmMjVKRceZSOteJ2Gi5OI3C9B0N5l28A\narCYoRzvroKty6Axedjl/K3UzVsBsH7uP44q0IDD5DKf7iH/aqGyNg81sVcZ\nE2PcaiLWGdd2Bp/1Kvy9IWEM1ldQBD8rDWbWx1kMxEbHnN53VV+Q7f6bTzcX\n9QrQv8srmtyCX4J/TqXuHzGL/aSh4l5JaKmLenTJ1H8m1YlmLhOJ9uC3kvRU\nbwEs\r\n=86EJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC95vO1TBbzSoaTt5kL6Sv23KQHa83pz3KjrnWQiUkeuAiB66HL3G6j9QfY7+z81Hu+WmAiD0mt6Q1ha1nZVqUnmLg=="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.9-alpha.11_1603975636065_0.9322250349437138"},"_hasShrinkwrap":false},"9.9.9":{"name":"micro-kit-atlas","version":"9.9.9","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"b01e89be0e66002eaffe40e5564e6e4f5843a6d6","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.9","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-lz6BBhiQFJ8L5M2PC9iQpr70RhdZGKSYzg9fBZ6RhZv8ODUktBMcuqj9s5I3SIo0mSu8iIhM1PU7mQQgY2tLNg==","shasum":"823616f4d041b434d8894379b2d89abe6f5f5456","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.9.tgz","fileCount":162,"unpackedSize":547341,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfm70eCRA9TVsSAnZWagAALHQP/1Ozid9+CXvafRyNMafE\nnz1XULf/rcBIUjndU3Pvn8TsalynYPm2l5fHg5L1NgbWV9ZQbRFXCovp8OcV\n3qT3R0C1GWmbdrLxOn1Q4O7QCt3h6aJpH4JapxV59Qhw1MgfOx9+PVXhraLk\npmPi3v5B91UoEVl9tc/rlT5w32NHsQypUCkQq/rKBLPTE0L+kp9gv/Rg0K4x\nkgU1v12EyllRHjOE9gyPkRDrKR20fZcpn52lHcTXNnFCjmwG18EuT8xu/GXE\nmx/fFLAK+sOEmUbvdteCve4W/nxg1YvlJKVMlgDVFgDYSGWis8/XwvSUWT1r\n1SHfV0e/tyNPBIWZpVn9MAr1xSmzFeExLbWNHAmEfnjXwfy+rI6OTM/HODMw\nq5MrFZiqCHHF8Z16AmBStM8Y2CppF6Wi6rh4VHmuF61H9hR+tCh3JepYEiGs\nnarvsSgs6j5jpAA6kXcJym4Q0fdKyzSO5kBLY2Oi6owBpac2tdntYFR6t1fC\nMqS8Yhys9oncb29Mr1BYZEpurXfdIoGRnt2CiprodUUaSQATweW522PnG2TB\nY9ybVvYEPjauZu851eV96QaDedFgZxSMkpObvH8FK1OMfvWQ/+C1USyGvV97\nU7RfWZppdVDv13YvVUvLSznRmQg5wB+QeIw4kELrtz1Tp7WNSshBPOMB8pQe\na0Nc\r\n=6j2e\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC1OD2gn7HKFiqh1cs4Jynb2wTESoryMFyXBDpX4CLWsgIgDfQS5Cgsqa/DvMhqSXID/TpQ3w16ZVVdFzJscAwJcnw="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.9_1604042013538_0.870242117079411"},"_hasShrinkwrap":false},"9.9.10-alpha.1":{"name":"micro-kit-atlas","version":"9.9.10-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"d6d05e21d22b61be25f343f3b77108242641a628","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.10-alpha.1","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-yu6mXorQjUKF4DpzvEU/KNl99s0z7bYn+aR/3mvxsTnh7n19ZDh9p5d0BbOhx6MRWJpsmyHkeGuD/Qd0pUPsSA==","shasum":"43054955a5e978d37fe71707c78759d7535d0c30","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.10-alpha.1.tgz","fileCount":162,"unpackedSize":548550,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfn9D1CRA9TVsSAnZWagAAuOcP/j0MqwjPnA2B03ClX09K\nh49LbnN2jWQKsapTj0C6w4QlhxsQqHnBS4d999/vNiIUBixufhHwNSavd+Tj\nknUqpOd0k5E4GK+LnJmsHPnNIbjRlp++i9LYmIysKXZfymjgiiRNNBj5blI8\nFlBwLkIGHHjegM1lygJuKk4/dTculCKtSpuG9e2o99AVpR37+xc6XvoUl9nv\nBLuzoVcTmN7dcV2OdWgD/rVYNnQSW32ODbxa/S+D9jGVMY1I8Wh8MYfN/fOa\nzQHmIAmuD7MrJe4gBa71WISlDKpiuK43Gfd4CuYEbF51PCErLthB8Azpm7vm\nOb4HodmhifhurzkN8YzVBrSih7zGLu9HkOIGdZnVwM8fGA8jbAiGMZlTYFHj\nMgrZGk/1Vyl8hfifAI3LHiYsdME1vpcTMCH+ZSMp2G3HtTvC7dj39tH4Mc11\nMRLwd5fZaIGhfj+f9hZdIRrxVGHok29P0HOHVcxEkemaMABxTvlKZ7Qfk4iR\nDWlCOi26t12qIX8KFQ9lglly86ELPn15/MJvymM1HwVZDvW6lSuoCAU1VMUs\ngyJ4ht6E5VPD5+1sWcx7QaPeWrfjTaSSrkL0Q+ONhuYmtUdC/A6G9MF0o2pM\nR4F7SgC4phJoLQ8wNNu1D5qli4xKVBxot4XzOTSqgs2VVBDOz5j3bAaopYkw\nLhsI\r\n=0iB4\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHZxhgI1tVQVkbG+AMyYqZpRvN0HiqAoEe6xdSZ4O+o+AiEA+/5wi0Zjl4KU5RR+6cvBoSr7p7Kc6cvN+xwNr0r7gjk="}]},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.10-alpha.1_1604309237185_0.20977313921665552"},"_hasShrinkwrap":false},"9.9.10":{"name":"micro-kit-atlas","version":"9.9.10","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"87e016947bde82732eea5381618ba090670b2c09","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.10","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-6T2fuN/rSOAHX7vvgdpybhvpmk0Wj8UYl4qAMROOaz/RJUrzLRKYQVuIZoED/jD6ATkGU8cQRtArH7xa/ZbaUA==","shasum":"1f60274ccc8623681000c3c305cc0d07adb877a4","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.10.tgz","fileCount":162,"unpackedSize":548917,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfpQ5dCRA9TVsSAnZWagAAilkP+QA4c4pIXAUhWXQTncrv\nMsTcEWVN9rpRjlHZJ/8jI0re7gEzjXcRCo+g8K3+jELSa5a18hAD530WIVIp\n5AbUrfzhssJ7eO4CtfzNsoO9W80+TQfPyY/kMDMxJ8qg2ZSJWgwhbLR1g+wM\n5fWbxNgUzG6USkfXxmbnsECsQwQy/tNqBAEJ8xzrdblIIDEYgmtr9xfaYjNA\nTXHzi+zY7IzgpAwCnkcD/EfJPxhQoUCLDwNvlHrOIDJW0cD2L3+odHupZgP0\n5SzRVPWAgAMRw61UyoJsIIJ0YSOc3xCAw/YRSMxhaaYD4ixP2Mw+SfcJ9dvX\nZWlVkK8DYbzKbCTrh0XfjgNUfHOPhDfndnQLezk/ms3YuvL4vMFV/jyN13X+\nEX3+ZcgV8W7yhlqML4RKBaepr+wr8d1Wb35EiYvF5uKwOQjz1R8/GDHL+yyH\nrUc1w4FTX4GTXt8we51EaW3mZKQXVgcxQE38ZMcwydghpTu5L8tERjsc22mY\ndLgs9EEpvnvFhn36WcrNxUCcVYbcWgVJZ4B3CjX86CicNQqXh5BcgZL2bAlY\nP7zoNXtIr+gkyHkqL8DJ6vtOsiQ9gTHLcfm61VEtlkkNnRPQXF0AZhjGWfCU\nhBv5SdWiaosMwmSAyaFSqEc2EMudIcDE4VAV7LUHxtkxK7y7yv7gpLe3ZPJ0\n5w5Z\r\n=fohG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBhk+vTjTRHOQvuYUA0QWVZ7pgCFcCHr0ZrGC3wiBYQKAiEAsferEC1Gr2e6o3leQ2EQIx4wUlvOfpj93YmfzpdX8ZU="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.10_1604652636677_0.6041122784004276"},"_hasShrinkwrap":false},"9.9.11-alpha.1":{"name":"micro-kit-atlas","version":"9.9.11-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"07508b1681a74dcf578a86450cad268226d842d1","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.11-alpha.1","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-M9tXsd2o5LMCN7ZObbZpVeLUFbQ8q9V8yPtH7k3RHJv2XbvVY9Ul/xs22x8ayxK1sbS1KMO/ZHZsD7nFsL0QXA==","shasum":"23bcdd24068b1afef0de4550671b679cb146cbb6","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.11-alpha.1.tgz","fileCount":165,"unpackedSize":550082,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfqnvGCRA9TVsSAnZWagAAHv0P/2ARwEMZGzftPFhnOXKf\nxG+eKqXmR/6azBqFvjEM03BoL3Nxg2nmwWz0LRTQe66W6zxiRRqTzrA2mAUg\n+/UAWHNZqWnGN9wWqjwIRCQQnaz9F/7wieDfQQQ/4L26u+k/OTtG/4Jp6epm\n6BrylAyD+rIyy5NMGikTZZkwAvgKTvWiNxsOT6/7ZP6ATec4ZFFsJFemSfdq\nl7p6PIL6SkwNu0ttu98MOQQUfEFjuaw9vMHPbcRqvQnw9LsMp4/iDgSh75/b\nzSDmYHogmtnPmnQl8daDKA+qQ+JD41MN6jYhLM49JmOavcS8IVqCAXC46ruE\n/wUuSVB7siCLNlt7mnR8xlGc/K2+vzIVziqmXGK78fzv++hkVNubkGFWxEB+\nxqtrB8QSgmxaTkO/Yhx8ZQdr/oYr7KudE3ZuTq2NPpkN0bwPPLGwiCODcZw4\nscxB+N7/mQGKLGo6oE5wkToGaMWqF9oGo12IynShVXM0EEVpdJxxT49KWd1B\nmVFMrhUQwFAVbTJz7ucZFVnpu9gipBWEH6vLbSD3Ws8f8d29zvE6OCEHYHFL\nE7vE/3+xUPYawu4m96Gbg8LozKPNxXl0MyAvIkvRykgEg31IfKbTIm78oKUQ\nSkihyxI9c78yTY/Cw6fI/pkUEdhzcZxQSvPT3vrYjo2hG0NAIFmnp+cGhJ2L\n6Qiv\r\n=FJe6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHWPmtqiM9YD++9/M7KX8GLA0NnEiiuBx89hF8ccv3CqAiA3Ii9N7BqP0nymNW2fyLiLBGg4MYvdjDu/2syxTIif1A=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.11-alpha.1_1605008325462_0.2946818763097405"},"_hasShrinkwrap":false},"9.9.11":{"name":"micro-kit-atlas","version":"9.9.11","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"07508b1681a74dcf578a86450cad268226d842d1","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.11","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-Vl/Meta2bjpx12BKl5+i25fv66U3Am4gstQu1t6UJQF3aO/rlO0yRxCFI+EBnujn7Z2FxUfmDfhVgc+NLQ6Awg==","shasum":"0846b9e1fab6fc93879cd27c542f2828f35e208d","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.11.tgz","fileCount":165,"unpackedSize":550074,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfq5esCRA9TVsSAnZWagAAX/gP/2FvTLZPVHca+X1Gb52r\n5CcThJ+lj4erCRq0nKFTF6sHpZqfVwZfR6EMwkgkNe1jxyt9X7FePG/62xZv\n0xY4W8p0riwmBPRYp7ER6wm+2nGOLg3R7CZp2Ew5f5/240xS92749AnHwsXq\nJKBMjRq229W3MDF8FvekZ3XpiJHa7KUDyQZs4w/5CBW4oyXRTsebLw0SIWgh\n2v4jO3Wwjf/YUv261adHfryez09BWHsgXWDv8qGbVSrMT+PvDNDJzqcCp5QA\nUs2Q4kmXEBa//lHHXCYsSnb1U1HLPO4kw0W34JQwA9aeuIeAcJVHmt30sJLl\nQSgco03eFHIYfCA2Gq7g3tdXM03fJGubO81MH8oVc1+Fked50NBBDtILObN7\nNxxoa8VbNatrHbj9V2c+O31kcGyNjxqZTnrCX877tnbXxzwh5HKOrV73qYe2\noUz18zxH9NZuDJE+4u7DoQ6fDCWt2OzVQFicnfaaMdEaNjRJ0sr6KFJhbDe7\n/0gh9mBJkqGFK9CLFBV1CiVy3yHZ24Yyr1XqurP3haxRU8wlo4uxN8aSBpdg\ntSR6WAYE0KooIppAT1KzqxBQIOuiHobxfryaSPiHAWfXwniQfob+0L870fKJ\n8UsknCjQQfw5vodNbaoS20eppszkdcHinUSEAiccOP5kwHGwU/T5h4m/L4/P\ns3fY\r\n=2W8H\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCLzcmk9sgirL5U5lxePD1X1A6zo33eWXKkZMJAmqtGCQIhAO4/+pBthTuv0UkNil/MaMbTkPfkV7QCx2w2QXnICna5"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.11_1605081003446_0.9874963418529012"},"_hasShrinkwrap":false},"9.9.12-alpha.1":{"name":"micro-kit-atlas","version":"9.9.12-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"6865660906f3ed1fe5ccf6bcbb5de0517137a363","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.12-alpha.1","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-DMKFhlgnT7qbueuaGzX1G2CAWRdoOt74JmJZNWEYXmFpV1zN7q8iqgPn2mT6cJdM3Lu+vX+m1ueXiY0LTQGgEQ==","shasum":"ca9750ad3296347f299a34dff7bc0e95964a1b42","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.12-alpha.1.tgz","fileCount":168,"unpackedSize":552314,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfq+cGCRA9TVsSAnZWagAAnzkP/As88ZplZ9bB2Oqz/TcD\n/rMxSHzYG0N26OWjH/5Ddl7FZJT1p7kg4AGs5ud8Alg6FiB1FUx/S0ebk7WK\npKItYn3IG37ei6lkhQ0uuuNSRdwsuU+G/v9fI2HBNCkkkOiuXqETDr2Ld+Hk\n6ytmMpUhbqASjBp/P4hROvvaTomTGbPDMsBVieQAam8IlU6+d55rnwIo+J0p\nWTCBBieO+bU9sg7J5cZh1XELc0u8YnDUyqforg6Znlk2lgxaLl+qhnG/sEI5\nCSmAPM8xypPxiMmZIiNXqoKb90FmfWYjO5DqvxHIKQVp6h1pcYuh4bwXwn4w\nUQv+rugYxpLCqurp2o+kz8ENhi70mPAyNIIks6gu+arsZj2y3rA+ImgAOW/H\niFT3yRsND7gcB+uIE/ZqTUsWfTyJABpxBT7GHtvogfjZhNrAO8SrKnA4b/E4\nXlFTAqidBJL0OszPuBMwyHmx4PGFgq5Uo2yYpCpzf6hnOl7e7QWqq2agrRHt\nJXxmzkZQ9lpOISvCAzf8EMgcsTfatkzhKXY+ZZSUH8iIQuQBMKXWAldccAJV\nNfntte4F7D6VOGqgm7hBnP1xnWz6CIKVpIwF6m6kzNfbAP8JTTkBNdqQFTa1\n2d+12ZrROjC7UVYI7z6WHth/gvvFYXmKEl4XEEi4hSMuqyDHZ1CAyF5jTfeE\nIzlI\r\n=3mIQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIB1KaIfswPwvYoNTrEevoc5y85CFp55isERq4VSXpXZKAiEAwnNcOZx1zSGt2+9SWBV6wn6jmP+6fEhNeWlhRUl7QPA="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.12-alpha.1_1605101318242_0.28023818507385445"},"_hasShrinkwrap":false},"9.9.12-alpha.2":{"name":"micro-kit-atlas","version":"9.9.12-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"c3688b88c2d60c54c6e34b80b84b1e2cd86a3e9b","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.12-alpha.2","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-CBSOHEsse7Fsq5e2j3lJeJ6zYPRQRngrNqHn6aqloe/uGFL3VaovOQRzuqps6vk7P+Q9OetHjpp4Yx0pRR/+kQ==","shasum":"302a86b0c46e6ffe91418353e87d8721f8e1516f","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.12-alpha.2.tgz","fileCount":165,"unpackedSize":551724,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfrkdkCRA9TVsSAnZWagAAVv8P+gIiXc5wB5yD4cz2SNPj\nViMh/B846gEQ/DtReD2uGIlZiFw3dt8WfJ+gmna769av/j0kB+sIns6rTiSJ\nMYI9cQo3YVxxiHbW7NqOL7PtAU8y7+s8iMLqz/R7WV77CS0P/hWCKjJCwZpf\nz3boKFHz8yXChKVsnaoxtFvOuuAvXw2mFlKYgjpFqeDDN48YhKznj9Y3BCpv\n9+aWDgM6dbzHGoTD4/G0VTZrj/207osXEQXJuK7zJzSJ2lvN00DIM5NdSx6G\nJAsGdeQ0QSt8ODj1rK7lh3JMMiFaESTUavGwl+CjnecZFHi90j6EW1lyQUgt\nY+OfxeIuMJcWv/flAbMzAKX4qqKt1oy/5JGCWLofgcA437FarubNBQY5DZrH\nNnXd4HM3Eeg6BXim/n/iZEcAOzQRfYo+flAxeAkv3abDf62Np8bnaRPFp0rX\njAsSofzSUqWdX9u9mC5lClK9Wj4Y6RCkC0BSfiddV92k/MpBsAnVp5R4M+JW\nsKIIJy0oq+80NlqBEEHF3cj2C96FruPDvmfP7kJZ8O/WGP3JQ0+PqhNowQaO\nesXuObfYLdlOyQnlQDwFDqeBOviTj8L+6v+broSdoNFmPIAxcDj8OnOQmlC6\nhJi6ob66FQfbqfIN9ZbWJyl8LicDWESGTKRz6itvwnRKnlWTwPCgGvhTR3m2\nqdlV\r\n=vDuy\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGJAjPJUZ5IRAzelj3CEJcsOYYjmy7I4d5/aXE7ZO7Z9AiEAswfcLFNcqY1DSoUkb794o6rARqY/lM886KtS61QNpT8="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.12-alpha.2_1605257059598_0.7022444837673827"},"_hasShrinkwrap":false},"9.9.12-alpha.3":{"name":"micro-kit-atlas","version":"9.9.12-alpha.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"6dfd8ab2697b75dc4e9a35b9643fd98f54b86a4a","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.12-alpha.3","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-HlwvrwADEw3AZCM02XorS3t82Ut5j1zM0kN7PCpgnHBRFcSWYC2Gdh1bD789KF/FKwd5xrF81Tg7n01L6OU6aA==","shasum":"a961f569842be8005e268a08906511936bfae515","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.12-alpha.3.tgz","fileCount":165,"unpackedSize":551805,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfrmSCCRA9TVsSAnZWagAAE08P/2h/S8E1tlkTcQAZT9cE\n+kaLKQm5XeSeD/+6VFGEbi9kbs2vlNdqOTiKNpz3IZSnKOc03I542J1DBPnz\nbU39uiUpOBv9jC7Q1y7GTExqxD/ccqSJtKTERSEY1Sg/uIEvdaMhMfnLg6/S\nMirgNLdu5deDoVGv5A1kavGMJy+x7mIcPae4Q2GoGkgnENAMZYWVWm0XnJeX\nrp+KckBc9X3RdTAB44vsP1PnJGMIhM0eD27DPCZTwdXBJijUpX4K9LYFpFCt\nLlvHeZhzZ7nncPtdNs072/1lIyHnHrRe+vOgw2Q5DiPzpF7MZSX/Rww5BhiE\nLrWfsxp3zQFphs86c8SGx2ZhJjPDZP5dtrV8YCZrAJqDbefAKcvVFh1XWTim\neVkSWfSFze6w7o92aFx85oKuakSFOaakzsSBv+4u0TqicwhJCZnOFZ+IVDaJ\n+AEeBnMmvyqcZqWB4g3lzFxnnYHTuA9BVSQkgIdMjzGfVcBeoCZVtXBEBkMz\nlvYHldIZ4OoURDaM1MZ1WTL49rN1b1Eg2E+e/Yk57n+VwTn6o0SDNpxj5F55\nRuWfkD5MePsMUPjQZBEeJSojEk8jRv+3zHPYeBCCArmhSeglWrxBHmDau09k\nOiDXKS6G4FIV5zEX9yc0uAsnPuHq8FFLCninItNP4WmRoPqnVBR9VVLdpoPE\nSBR7\r\n=1QHf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDAg0AD+/9dR8W3pFSxwRmYpFQMlViC3uTjZw0Yr9k9BQIgIcI5/NXELtDR7loLH+NI4fFSuBy6KzyyuyxqCOuevlA="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.12-alpha.3_1605264513424_0.26706674474152825"},"_hasShrinkwrap":false},"9.9.12":{"name":"micro-kit-atlas","version":"9.9.12","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"f4d775270b6251fb4a99adb347175e888db20401","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.12","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-9YP80bgWgKJOzS5U7KEw8KCryaYegfF4BPxOoTdUluRL+8JQkB+YF68FVWC7SeVzr5Vo4Xplc8Bcj8GxneIQzQ==","shasum":"3c8bf64419609e147579d216edfab32170cddb67","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.12.tgz","fileCount":165,"unpackedSize":553570,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfrnheCRA9TVsSAnZWagAA01QP/j3dENWmgXTP8RDadX5m\nfTuNvw/I/JGG7qRSh5fYpTbkDKpx2HNwID9yuNJ7KSrP/3zxvV8ljk0jrc86\nQ6BTxMp/mbm4oZDbIcf5FOWtjAoEMSRMaf1gAyIeK5pFZcRxw9kd3Qm2ytiO\ngx+b8XUlW6EfGv5d2wtZV0jFt2FVdzWX9/mNFqo//BuD0A3DMrf1aRAMQbDh\nJqHToZ9CT2O44DoUGNEFJGFpWn8oB35qpf+F8j60bZmkolVYmc4EqPjq2i6U\ncByxCksMimEVMdLZAg82gywJWXD5IU7rd184wEHibGt/OCuNxKWVu0XfSJ/n\nxIXINut8Ez57Zru5NN+Qp03kkiLaId/yqJhmH4+ulz2hG9Dr20kd2Z/P7A5U\njvVeg3O+vTb49HTazNuVzoYM2pZIkU/1k9W+6lPPuCX/HnViw7YCgvpMYEED\nAtSunEwMKCvHS3Z0z2Sf8JSdxVS2isVCb8isSWLeZvoW9/q6EMohpLsVK2Zu\ncAw3aL6gdvtRCqS0YAfuwsCLWkeX5Kou2ahdQw4/u/NEC5lge8U2okXOda8I\n1IM/acv1ZnxemGinuvymFfeW/MQZi0/m16vX7KeDMRDbyI6o67EHIvuRFQCY\nyWGWxnmPidfS6f5GjtClOMfhYjnJoeQ5BkBYO4RkpH9eZV4Uyfaledjw0lHe\ncVna\r\n=VIb/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBeVHKY6Xb3X7J5KouWtPxxPogzuoFGNmh257dDoTJALAiEA8lBzYhL9N7pmwuiMpmamttgbWBAOWpTMrZd8sJzgQsc="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.12_1605269598136_0.6615563330114091"},"_hasShrinkwrap":false},"9.9.13":{"name":"micro-kit-atlas","version":"9.9.13","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"f4d775270b6251fb4a99adb347175e888db20401","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.13","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-84ugv3RBmAKPX3V5yCB7MGfrGg1F7ULAntLQgv5hjfaaIbTQujR0xEeJinFjrTHEErtxFH++cb4/SjWbhvtFIA==","shasum":"b7910127fe6399436bfbf7c19342ec8611fd1eed","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.13.tgz","fileCount":165,"unpackedSize":553570,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfsEioCRA9TVsSAnZWagAAuNMP/3ySu6E+xhTQ49s8U+In\nGHEzxMbxV6RJTeLq36mCHDxQ46apxWWtcviylvSnvU97mQ8yv5Jr/YkJ/Xke\nda5k5xPDuQHcjzg04FetgNTp/1otxEuRWw97c5gPDnMGLXVAJEy6wC6j/tVq\nzK88CdDWOh9syYBSNHUBiVr3r20Fb7YbcS2dHZoTCZbuswYNcAC7WNpyVWrK\njZxcqZjqPpTOSV5UYeX2X0spVfmxYXmHeGf5YH9hXygqpwJux+MwlsYCd/lE\n33VociW6schA+1fiSFLbGCc/3UBkci7jOfZ3ReAGtw5dA6NfaFs/DK7mLdSV\np89VVwfXfvuBLEOIlCyr9mOr7OHp1ZDdqRUfyEhKQRee4EHvhubIE4laolEH\no+VxlNFnSFVTG81eqvbeusPmAStW0bRDqqHw5XKp4VEZSgi8rqD2EQ/spQjl\nZM+bPVc7doi883l1tmw94zi7O5876qNNmZb9PaV2aJ4MVV84wbjm7/xovZHK\nVXXyDwnjShu2zQaYysxmWzF+dmMYl3wie8kKc6hvRC4U5CPcDPZIc3jVvRej\nPk3CwgXnwmWwt6Q7Cnq2XDvWAgL+OgWx8ypoYQncO8ACI7KKClRkdolK+/4r\ngvXePJqxu4WVFuiizoZYzs9evNnYu0104XpjTpFVE0J4nldOEJ1Vlnox9Z57\nNKf8\r\n=ODMK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICuywHKRduIXZvZVfQaiBelmZOQjzmIofELHMlwbERa+AiBH8pikkBapli5hTbfoMOcnCfzZPXKxmTkwzB0QT+0oKg=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.13_1605388455337_0.9229912624222758"},"_hasShrinkwrap":false},"9.9.14":{"name":"micro-kit-atlas","version":"9.9.14","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"b53d7024b8998a1fb0a6b4f82d92f5d5a9f3e2b7","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.14","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-DsFRjtTJHXX/3O64g7G3MCIEA7/g67RJ9vxWcg41laNV5Mty6y0jzwKZlSJHH9HdMTj6Xpfp5C36cjUhIKUPcw==","shasum":"7aaac39f14b0c2e6afb79e548ca049c54b38b940","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.14.tgz","fileCount":165,"unpackedSize":553220,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfsWmBCRA9TVsSAnZWagAA5vUP/iH+WPY6UlMj37GCkmNC\nGVCIMqvu39wb04jtnBTLeYCAJQ7/H+F32yyhghtC0MPLLF/0FAc6ZiCfeMyr\n+ayWu1iDNqkDGeQw+fTKoSg77KzKVFgTKG3j/J86D+GUhpRO0gK28P31Rac+\nhzA2BNmZbKP4TXx74uroU+3g5yrni2CR63DqVBOIBRK1oUYNr25q5pEoOb//\nF3hTMGQZGmvb4gqhF6afiEaO82GjJUJKE4EEPeovpoFm4iHAiHp1DAdgeNPh\nQyZ707s63lEg3lvhGsRf0dTL/bPqfPFN2iZVoi/lKmpKN3mPMofK68NHN50+\n+wTI7hp4DcgkuIhDzpwKwbwLsa5FJvTe71Mjd1wbbW9Lbb5Ls4WRRnthLOQ3\nTleGZvkSRluyrJT2PL69R4GQfKxEwJn2IR3EHGUQELS5GB7xqyoNUkYkw2Jd\n9dfeY3GT1mSTJxG22KoUaEftw2i2yntFl77Bb6c+3aUVGM1gg0p0KwQ5m956\ngb3bbghc3ylAaDS/3HE7z0fdbzf7t8SeOWDsfZLwglBq+Iey+jqEfK5pxCym\nkELSVz/W4pvVtxNjgkfqnrx3lKW1vRfGgpVrtzf6CojUO+eb9sp3/jpUNB/U\nKrLRR2JXgMWEs0X2i8K2cK1zc9PtCpxGv8TyMgffLi3HOps1ctjI51T2CtY2\n1U/x\r\n=wb2e\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCA7ovM+kMIyfDJ/Afrjg8aysk4FB5emvADZVQhVpkySQIhALA2cRlL+87HmU2BNDzE+GCykD2X49bRETZoZhQ9XneE"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.14_1605462400355_0.2565369940891167"},"_hasShrinkwrap":false},"9.9.15-alpha.1":{"name":"micro-kit-atlas","version":"9.9.15-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"d0c75441840e1e05cd5afb1f1445fe0154681bea","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.15-alpha.1","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-dRfJoQ5v1xcn77PTRWKCrjXBhNHyJq+ughTL8xq1shKbCKF+l8xcgqasJkIDfY5759165uEOJ0f8xxN+stlUqA==","shasum":"6db98e6ca9f8184e1f14709decca2f45e1e34d92","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.15-alpha.1.tgz","fileCount":165,"unpackedSize":552604,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfspXQCRA9TVsSAnZWagAABYoQAIrKDkfY3xhwnwIl2aBg\nOALIcYgQFnYhsbxgvhwZKWuByiyRrOUIibNEhj+hXDfpRApXMd1+EqQqrVTP\nmzZTYDQqEnx/FcUAw04+vySj1JpDmSnidpGv441I6LsiytnjzL/B46HXonhG\njlz78PWkIjzGgiTKWxZbA6DkbaGBSbLLInO4+HPnohCFpTTR5XQbqoknKs57\ni/zzI/+nieC42iB4LKGZ+PUb/x45+chwyWWuswIVQ+qGA/1YGU2uQCzFK+0H\n7yL74FUBHw0qIWoaE/k5EgQ8iAnsF02p0zvHz+BK3GElSqY9a8DvcHn7ZrqH\npWNbsKfaO+T5zdRprJkwbHzkfLVtm33Dc3UshlknBHv8TMi43MNz9uPkwiZr\nDDCcjZIsLUS3ksgGzMFDnIValEOZyEJlgZdBknLBldr2Hfzvv+lflUllF/j4\nMh+0G0B5fXLrTV3GUits+1ynWokBShiTx0iciEUlSgl1wk73GvMrg1DL9SA3\nmzsFqPddMGS8NPL+Etex51OxZMGq8p+hzibOoFQd4jnOERT6yPO7F5mSWTyC\nO1V4hJqVaFaty8VA6Ew+QMrp0cMyV7Z2QVlsV/TQHBHtdMq26joVk/A7etoN\naIdpqtBBRv2CxkqI7ff7rtBK+8ssmUbBRgYIEO/cQJC1ROxShwumya9tpmSt\nO22g\r\n=YkgF\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCRxNepYofdCunaYFXcVSag+rnNd2m76Zs0+E5e/IUbrwIgTlmSPnRbYUmZzvdh97C3E2VEHDkiRgTFd8gJaAEwT0Q="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.15-alpha.1_1605539279828_0.9960525311650661"},"_hasShrinkwrap":false},"9.9.15-alpha.3":{"name":"micro-kit-atlas","version":"9.9.15-alpha.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"7ec74c5a3936bca40c69223c2053910cf3e62ca3","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.15-alpha.3","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-z4axuFiVgKsRrXIb3W5iurYi6D5i1P+2VFfff1jRo7+gDog4ud533dw/upWdUklh9ae7M2BQIdegHIVeFaTm1g==","shasum":"9fb761850973c65963cee526df1ddd9d99705ca6","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.15-alpha.3.tgz","fileCount":165,"unpackedSize":552602,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfssg2CRA9TVsSAnZWagAAw3EP/A0SQuKciD+8rxGnUNog\nhHJ0CByk80hwNpVBtzIq3DagaVe8z/OoIoz3liHkQSKkkcbBV8aGgKopd5LE\nPSuX/AcB/G0OzMregGv1YVFV0UxqgZFf7BdyoNd5eI9vFwW+p7EJ0O/QsWGm\n9IEKsAeAJP78tZ4wiJ9dQcZHecxVBJP0aMj2N1HVOUlOSxfTYNuic0JAHLe9\nhUF4NmmkZ2r/dEPDRd6TWPXggS7rJpJhVHf5PtHl50Myj1kt3clh2DO8VuGi\n0HJ8PBG8Pjq5D0v3TgBNHmAOltwgYbjQZfXUJsr6jZYVQ9z3PQGUzBhZ/j84\nu9FXEExYm875a/grnhCqr0zng6X2xnA50N/dmn8l95ltsLe6tGLdaE4vi4ur\nrAAQUKg3J/+ppPIUjmpAqyM0xpvj3mCBTpjzt1DJLrJi/Lsb99dDyR3BdYMN\neEeN8XbQJH6bz2z+7bwmfSuzJsIcQRrap9V/tmzNEK7bhNwOFzJxu/udM2/0\nZg9cp7mRfYfRkOO9nP1+Mf21HMXm3LsKBZ/SSxsDcF0r2x50io0KtJ2d9wyR\nrrXPguAkHo+Dw1sOSvsfDRh0lTe/Qy9F1YJmKt8zGd3oSX3C/HAQA3nH1Lt8\nWZOqYdRPrHwN32a2CrLjWuaZkjftRr/lO1pe0otg6jkjPiP+vB9BoaPO0x+x\nEjUJ\r\n=QWT1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDZxmJICNmU08L6F5Dlukad0J2WisAOmcInWh+GflKLugIhAJ5kwFE7bGildZ9c3Y3K2PyvmmBm6/MSykfINPIyjmOk"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.15-alpha.3_1605552181631_0.16292899082487766"},"_hasShrinkwrap":false},"9.9.15":{"name":"micro-kit-atlas","version":"9.9.15","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"e5766be26f09f66fe75b93e2c9efd579eaf63faa","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.15","_nodeVersion":"12.19.1","_npmVersion":"6.14.8","dist":{"integrity":"sha512-qJFgZXrzcTwQFywoZgzxPovIM1PXf4AUbI/CPXzvqH0TShqB59y7XFjl1H9vkME5W5ix7Xvt9hurI58xb2WLCA==","shasum":"f47222557da839ab83030d7e74d279702cd9bc07","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.15.tgz","fileCount":165,"unpackedSize":552594,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfs7FqCRA9TVsSAnZWagAAdi0P/AxlxRpf8IibwvG7XLs5\n42XkkY/SoWrf1s7Pmq7dQOKaTx/jfVmy7iIqPUQsqkJsETYoBvH7Z007U2Rc\nk+4/vge67NeeB/w9/7XTHYf/5EVfvpSJ2+75mmVM6DbJjVr4Kvwvi8VLwRS5\nRjVUuE6D1US1DBSanD1Kylsaxj4K4+Kxh6i1DbByznTGRrV7YQeV85CRdlH7\n04WTOLCAkFuQnDoVwzNK8z9g1192XFDQHV4mR2b9u5apKZ2CbdgfWaLj3sf7\nxatDM2QIpKRQvM+h5tqNj0h/8f3Y4UsQiJWJ3n2KUeqLZyBj9IMIRsX5asE9\nd42su9GfJ/sazA1MBNwu3mnrDugSXJs7Uyz5i6Utqq8ZYoLjgnYTEkeV8vxj\nDV9q50noKZM4dEsZ4HzWUkt0oTBmXT11moQDOPkjWxzJkFsIw/3q9VmNKppU\nLj3+MYKwonPVUmaedUiYRNspvSUCQjj92SW4lx7sGCizmYmZ7nLv1BTIFu1v\nRpUbRPG5B8fwMNqPCHNDnxcs/BOJU2tBqhNogIHC8yhcf7lqznV0oqJXW27N\nGAoNZZDm0LIgPTXvhUF2IV2Wcwr6GLWriEvKXg2scjwG9SBXgjypW0Ne1jah\neaSFlZSi/Clj279rcaUE/eJ6pOUJw8SskFh5ICYfAsBGJqniDZJ28JiVzYAo\nJjWd\r\n=BHgX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDtRcCf/KiUH1FUJwZOUv/YaS7fxW1ssOwbZNbay+Im4gIgQ2BX9gcmpgntlNpRsgPLJmmu6VMzHvujwi2jQeCcQns="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.15_1605611881408_0.10575291422812394"},"_hasShrinkwrap":false},"9.9.16-alpha.1":{"name":"micro-kit-atlas","version":"9.9.16-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"c792ff348c09d11756cc5f3dcc15a57bed062f61","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.16-alpha.1","_nodeVersion":"12.19.1","_npmVersion":"6.14.8","dist":{"integrity":"sha512-D+7Br3xEeNOlibaZKl+lpQWtaDb5jOecue9m8yObECCU3BaTsDVn87BCxQgEFPPBPUQOV8bfPpvAVULI0foLQg==","shasum":"5aa1f043b73705f6fcfb9ab98ec645bbfdb04144","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.16-alpha.1.tgz","fileCount":165,"unpackedSize":556177,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJftnGZCRA9TVsSAnZWagAAvAwQAIfUo5D7ite8hYjbcui2\nAoD1eaocVBvDMRbturlvAEb0chWLI9MKzXMACWXE8mZrpKZ+uJFfzuLQjloG\n3/WG8mc9ZjL/iTC0lDNiCbLrukomwTftleLw7180lih7oom4yKswewZpNt3c\nXY9MIJyCX2YnuEQJVd2Ig/gSAMkKIMucbmMYgw7Rgg4ytN6s3hjgvMmOhGlj\nNlJ6iZKeFgX9Heeg9Xopqq5VkAqmMeHa+7SA81bjwOFauWzKLrhJJ4L7d549\n8DMCfvbV+DyBeaABcujqYjO6RBjGpgLJt3+trxECaE4RRat5LxlTdbWfZ4kT\nfAlCvL0QqlzcbXIooLFGI7tsXY5fNXrXEnGYRFgREjfA/yXDEep4h15pJ9s8\nEwfLoqolkJ5cl/Bzz15t5GldLRyvmk3J4O5cboCUKmWUR6VPMEvNEEods/uB\nGrNNZRZ0KRvKSmdb8AHV1fOzjWowoPXEjvRzq5SqafhWS36gWviz5f8RVmAS\n/Z5DIf4wV6bgTvHmIELPeQQT5/QgdR6vh/XB71K3BgRiXgfhZNe2l0d5HaxV\nvEwy6r/e36Ttf21mv2EaoBm3sP87NH/1QHeTv0PMcKoCsx7Z0ODM7uRkupLx\noInI/+G9oOHMWsYcIXE8MiHseTkBNph3MZBtgTu9hi8qkNa3tLuFVhMlOALu\nF4zU\r\n=i3fL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEkFC9KKDTlgEi/TI8MxD7fL0KQBAuK3TUedSbAtxdxBAiEA6Q5t3PQ1G9tCXHRBpPKknMllzMuMcDWm5wc0CeDp4ug="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.16-alpha.1_1605792152317_0.13340270925397046"},"_hasShrinkwrap":false},"9.9.16-alpha.2":{"name":"micro-kit-atlas","version":"9.9.16-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"b65828ce22a77548b817d9f12caa13d305092e3f","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.16-alpha.2","_nodeVersion":"12.19.1","_npmVersion":"6.14.8","dist":{"integrity":"sha512-Rhoes3sRFN8V9T14W2TKr9QXlxEzObeUU0SCWJcoM0ilLB0X1Rq95g6wUt59RHV3VuB69ccOQ+qAWtkbGEgcVw==","shasum":"81c6c4d417d57f4152cd3e3d5384b8674d8c3c31","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.16-alpha.2.tgz","fileCount":165,"unpackedSize":556277,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJftpJrCRA9TVsSAnZWagAA46kQAJ/Bg+amWLOHMTybuPep\n1fOKFK/nui3DbKAVnHGxlyKZngwOMgiSdUAItJjVcDBrkClG0KGJ6b6Q2uhN\n3bezWwlqbEsqiiaaqA8rOR3+T7JHxeiNVmmfbwP9ouCOH5fkWEcegNsPOj1t\nH8LuA0LYlNaoL63mzQQ0KaHjSA4T4iFyFLK8qJs4oh/n2lyJHdcyQHu22ANk\nAn0qJlIq/tbVm3G3wK8be6b4aIExjbbFg0ovEet3cwbLSgIeRFQWpm6iNvkN\nOK5MhZcUegO6JurJBHkSufk/9Fawl7OtEq4zICsl6LJoX2Espc/btx5jQF0W\n7X72qqP8gaDOwijMa5P9EwoBHbf7RVT6bWTj7P1TWUqx3oTT56LEv7AbSfJH\n/ydHSCazesjZsfZl2zpbyiuQfAgMaVWYIHs7KBI1DDCcmfR7mESHrPFa80Sn\nfErEp2WwaPTpxlBfyCxjVHvY+9hpCX/h212vmSyeuxApHMf1ObMQtQRAEG8C\ntUE9go+gWIgW8muZZWSAjpqRSd1j7zzgY1PkZra83ml7FeONCXahHwdmK8Eu\nQiLkLqXfCdXRNWO+v42SM2sZH4G9TKvKX9ayt3da0c9C+hzhvaxNLEsM5m5i\nuLQbjqRqZcwvxB8nbUw4hBCB5j6plpa99vrij+vTDP124bvrck8+BHUD9d+s\nxSYi\r\n=cBMy\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICjuxYNGvDkzUbEP99ryOtEphGm9k+98vXl0FvqX5WF0AiBOJfdvzUw43mFPEKpqwPVNb8uvw2M7L5oHDMOQWYFioA=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.16-alpha.2_1605800554591_0.8407259806658409"},"_hasShrinkwrap":false},"9.9.16-alpha.3":{"name":"micro-kit-atlas","version":"9.9.16-alpha.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"aa397079c4fe01a7512172bacd933f79d887b093","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.16-alpha.3","_nodeVersion":"12.19.1","_npmVersion":"6.14.8","dist":{"integrity":"sha512-HtkJw1WYK7JRgG56Rs+nMctkf3rYqtJMqxVHdeUr8nebF4Q2xJhRD+QTlSozYeRgbBb7PLU0vlceEDF+BPLHbQ==","shasum":"2f27858bfcd7f6c710e661fbd0ed752e8aaee549","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.16-alpha.3.tgz","fileCount":168,"unpackedSize":562829,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfu/KNCRA9TVsSAnZWagAA9nsP/1ag3HYFab+SdfQ81bhk\nFtO4L3YwRetWGGBBJoM30w4BAPbl48Nh9ONp9kDNc6CrouU2Yen5T5pNJriR\nEdGAoRCI3XElGkH/QRzPVvQEnFzMTrlt9wosJX+nn311uWxqaTTnBad87Jz4\nXtXcVWTuDjDUd5S0u9BciLuouh9OkAwbkfh1W+volmTCKGj4bqE8ZmriR7x3\nKfQomTi1jsPgyz5ux5Wn2deTMC3ILZxxruQp/F84BKfcw1pX9dZ/6Znz+Pai\njFLk61BWjp6APEZNcmLBhEnZgth1uBIGG0R7x4aXf25iT9Y1fwYC8Qq9/BjB\nlSZCw6D+hc7BKl03DOkllrxUmwbEQhK5fYGuhZMiEqaBEXOf/buKIMh6fYjF\n1Yk3caHoN+qLw/vRHelA3wdChozb2LRMxpLIErSlByT2dJaQwhnhI9/s887b\nGdXaxBmqOIcF83eXVbnvLq0K+o1NpyVZpxiXnZyhPugtn9HZknC6nJHx7qe2\nJe/m5Ks8Zzm2o341k2Rok8co94nR/qRDJtK8tiNdQTjvkthW7BiLO6uQXypd\nN3se36yjXX60/POpIkE1e+jCbZXF/02gKHeUIzM+rGpNkZdQ/5l4VXO6Nf8M\nOih7aj6yYoewWNyad8bjQJXr1NXNLEy07xLn8GomDzUVeX9Kxzg95kvY5Ukz\nTIxN\r\n=KZsg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCMbOcNGE9Sr5cs2E+xTs8pQLsB3HjkJZ+A2HigqG8YQwIhAPfbm3vXxQGkKNv0w6EJgPJIjiqf2Jr9qQyiOQ66oyk6"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.16-alpha.3_1606152844703_0.5013801179689286"},"_hasShrinkwrap":false},"9.9.16-alpha.4":{"name":"micro-kit-atlas","version":"9.9.16-alpha.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"d1a4266d0c6bf146869daea5445526b76f601f9d","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.16-alpha.4","_nodeVersion":"12.19.1","_npmVersion":"6.14.8","dist":{"integrity":"sha512-5kgdJA94+vOgN7ev1Y0bja7349U3jv2dyslLjSN6K01Y7iJNLXRUNs1oF2697vJycohdJ3RAkESl9k0ARcAThA==","shasum":"faac6095d2c1a8b8535c6ace12d2eead2fb85650","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.16-alpha.4.tgz","fileCount":168,"unpackedSize":563184,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfu/6bCRA9TVsSAnZWagAAOfsP+wbXLDTXO5dGJvPilNFq\nZD6UhrDdZNVOrUxq5XLIUctZteqY/LNo6edaBtx2HtrJH8r4uI7gDB2fyetz\nbYFpFqZIBAxJcJgEvxxvusBDTGQCJgPJhtrh+ACWY0rmXLNIJ3vB2VWqDo4y\np2MHa45lHuh3xfo3cxmi4eXqzPTPAfct5z+q5N82Ivzk5HOIxlRjwbt7bF69\nC1aSdA4L+NWbSsqQLdFUnIP0cf+x8u4nb8WYAZj6TOQy4wvkrJ631sZUsib6\neGXfHIZu0c2Tjz4U0uHAFMLyxCYVQN9HSFfTmSw1+AP6oWhYHJMV+BQcx12j\n1QutqoWhpjavEVEOQ4mBWBqxZcBxSlb94TB6INCW6+7XcBHJfYMWuMzcnAkq\n4BJcPBwhw6QqWoLiq93dxbeWf2cNavCWiTpvy3swu5PAHFCQ8KJoNlLSp8Zn\nPDyE9CPn7o43xvAt0BaL8YBeGp+lk+z+TsjqSrXLFFz6jaCkPja6/jF0kR7x\nHqqyfxLiDww06SQYWGgbHEXkcedCbocHQaiKtY4vPVIDvOVzduRZCofSLTvD\n+q5mJop2Vd51d1sU2YtDW+Z1YkbGRwML4EBPRvpPhOuGWVX1Dm0xS4NQ4xOl\nk0wkJ+HF1N7DO0zQLOs7NmZrJ1zDwLMfVOgdxZRcdIYdxTwCNRSBZiZStW8E\nVIu5\r\n=BL7S\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDOD3PQGkG1ewvvSwbm5EY6rtlFhX9i8W2g8nc8n3Ny3gIgPCObdNUiSRYnYDbp8znwlNVbArSDHUuN7zbkBq2JPnw="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.16-alpha.4_1606155930522_0.16329200767241137"},"_hasShrinkwrap":false},"9.9.16":{"name":"micro-kit-atlas","version":"9.9.16","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.8","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.6","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.162","@types/mocha":"^8.0.3","@types/node":"^14.14.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.8","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.0","nock":"^13.0.4","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.0","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^5.0.0","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.0.5","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.779.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.0","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.0","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"521401bb09308c58f8711435394bcfde9f28dd24","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.16","_nodeVersion":"12.20.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-0hSFjRW3hIbmkjfjT8Xr62sGwdDhHiS6gLKkxoFM2bRXiNkoI6/s26YCuVMiO2LPVYvd24ZRcWVlqXoqLvEpiw==","shasum":"66f0950f01d38554792bb246be59e65eedf9bfce","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.16.tgz","fileCount":168,"unpackedSize":563722,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfvhDQCRA9TVsSAnZWagAA9RwP/RQsj1pT4TbeuWBNz9uv\nQReMXwT1OQFWt2B41L2mlLqnmaiwWyjFI1xAfcaouzsLQ6W7qYxag/iHwtxO\nX+DEQfa5sI57qTp3dvWKcDi6Ti44SFc/uOu2qOygQVToUZPJdVhOegCTHUAy\ngNuYkAEnzL8gGLMgpzFixmDU9rM0zG9KgpheG3Zl+cZZRZgRaJKzG4Al5i3g\nYvtER3354dfpL78yIXyHY9/NmTdqugSOYirdd8+X97ESJsM78GP9Td6jkgly\nKCf/DAtR/0O72T9pKeO4ydCAcJpa3RSCCiLvZrrCLovuDiBYjA2fxywKYJSj\nJPyeNgmSOB11IQD80LacoBG4yIpsVk8ryi1GSzn6aNFH1LObuLCioTXe6nMC\nIYyddH3nD5MNwscirsyF0KFocaGlcsXQkV25b+xFCJ23WIT9gZGt6WPHuYUg\n+yoDBg2vKlqyc6fcvCJaoSJWateUisrwABCUAlGur28Ut6fDxJBpZlbVynYB\nf2+OyOTUbAaI0OYh2aHIhgFh3OoX8lmSL/9F9nVADlPxDRqrltrdB1LCXQk2\nv/Qyp0Nw1/PR0OU6mTDzhVqrSO2lKKbcfF5Mdxi/sh2SwvFMzZDg/7ZgGQDG\nJCBWgqwUu5j6zbjlAFCqv6ziqTNzhPzBYl840AeZ3MlBBkcwzij03STiq7Hz\nGdMi\r\n=uPBp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDbUwuzDof+Ueol5UN9RYDNE5QWxkXOZs5Z7zkEye3dygIgBXXhUuzhHCjjo/Mb79OAG0UOtEO1dGv8NMQLTQ+ynRk="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.16_1606291663697_0.15441538224158124"},"_hasShrinkwrap":false},"9.9.17-alpha.1":{"name":"micro-kit-atlas","version":"9.9.17-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.9","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.8","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.165","@types/mocha":"^8.0.4","@types/node":"^14.14.10","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.9","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.1","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.0.1","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.2","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.799.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.2","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"3ea4d87843f127d4ef3886fc6d76000855240bd7","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.17-alpha.1","_nodeVersion":"12.20.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-mjj7G6uDbS1VXtytZfFflIVv1Lqg2YB0BRBf4+Jl7c9YyyIsajvHaofcKNQhyy+0woK1Zf3RygoqaQsZVys7/Q==","shasum":"072e3c26a9f286515d3abe747a3afdc99912e567","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.17-alpha.1.tgz","fileCount":168,"unpackedSize":568861,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfv7hcCRA9TVsSAnZWagAAKwUP/iEh/5cj4C46iRz5kkEQ\nVaTUINxD+mVG3jxyw9O/u6beBq5N/AofeULlFB1GgRUI/jDmcqyz5IpZsppv\naBbVxrmiY1lIQgZ5z5xsB7ZynDAzoMhX2khJvDONYzGhmsLTVdy7TQYziEDf\n2WftOeowDhbDHS1SDa1PTODLVHru4bp2dJtkzPl7DTDDdTWQe9X9eZ/btHUU\n9sbzLkZyl3nvHcP2O7u1kHWiLCKWfHFSNw2YTtk+e1ZhXmgiD4rmd43rsXcL\nTAYyRyJ8DtdaUFXRUvFDqyTrdKcmQh2TOV6uDpXPK3HfBKlRlg552AKH/AJL\nhY9ZGrrltGoPcFswKcIveoUeMUYsB6BiXekxW7rTLYelUIPLoCDZ2B9cgRk4\nBYHqxPYpTNJTOJMc+kK9NtZGliFbMJqKbcAsYcen+u7AucVguqqJmnhqb8cA\nv5vpPDCXVr2jgfGdR1voCJwlVtg4BTtHnQoKvybhWyhxXvtSHdXaYTW5y84P\nsiBlaQKueUBAJXsVd6TUeylapsccGMjZsWLqyHpDenQJzKA/D9kYcKM03RL7\ngBy2iUktIyh/i0sVLfDBXTvlCqDA75LmmymZhIF7MtSqcL5w0XZFl+kFfmqO\n81q3uRoQPPbNZNViTNR4KxzcyZ1zYE/1CZUyRC1GyQp/8HESV3n5gwiRsJsg\n7Q1E\r\n=kkgj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCLqc330NbP1V/qAQvUOKE0cFGsHU/mYhnyS/3tx+gBHgIgC13nl4QKpzwjQudchJ7XrU+leyXwhGZfsKeaSUqIUYs="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.17-alpha.1_1606400091811_0.02124489527420903"},"_hasShrinkwrap":false},"9.9.17":{"name":"micro-kit-atlas","version":"9.9.17","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.9","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.8","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.165","@types/mocha":"^8.0.4","@types/node":"^14.14.10","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.9","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.1","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.0.1","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.2","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.799.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.2","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"95d7cf380aa32e0f204dfeec035478a6480084c2","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.17","_nodeVersion":"12.20.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-MBd+4FA4/doTJ+j5j205sfpEFhC7avlU3VLkwujq12XedlxgKSqIE6FDmJfIx3jWJvTfw8nTIYPB7wYVtVrPaw==","shasum":"d8cab4d95107a2e4162929a3d2bc34ca6662c67f","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.17.tgz","fileCount":168,"unpackedSize":568853,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfwMabCRA9TVsSAnZWagAAeIIP/jQNHQzgYPdcVYyvmXqH\nrnFnpIWlr0/zO4i3DCDY+bQraMGrd9w/7Xu7L0DDrixa32hwWsaub19oZjQx\nemXpjpmUo61cfwjMdw0lYB3fRnPKbj/BqUsoe3H554Y/z8PEGMlTDEIAs3XJ\nKUNu4F/S++N+qAbl5z6sHYJr1kcDOh8YE5S9RkTgztOv/+/KcZ2C1aVKe6cd\nkbFlRr5GoThJVVK2uCQ68AGoZvy/FBy9ANE9U68Bttymb5dLlyopduYUsXwL\n27sMXELtm75T1xVkaHX68sZdB28ATLb6DuH0HSYWseivSPH3oETB/ZyLHGqH\nEb7ZN2Kw+zjXY/8Gp1Muv7vRcSyauJbaTpxyhweNODPMgY2TtAMpBpAxarza\nA2jTfMC+vtALvZUYCx6RPuXaLbDRsvPpi9Ph/tTIwiq5/5Z0mzlxFFVTAwNJ\nwBi8CY1tsWG/SdHOu50r/DvJQESDPLBr3/Trw5WYlP8Xs+diyNU7YY3Bkf2M\nIQJ/jeyZKadgLOtIseRDpMBYluLbc5Omle0fpCjMRRLia1H3Es/P03o2TB9u\nIYS29eE+345bfG5rxOuTBI9zIaG4Gbc5dM4KIRPOp8Ob7WkedFRbhrAx3KKg\nuc7M46VgdhajCoeMjm1JEQaOfx1PNYKD6G3v5T7BbigMfXVxqZd0soaOokBE\nYGU3\r\n=F6TU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE132mDqk67KT67RlCiCmFI524KmrdKjdAUJBNWi8PpHAiEAl0kwRsQdzUiUH29xrFyeo3TMuPL9HSpI9THgP01FyUI="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.17_1606469274647_0.40524900861258994"},"_hasShrinkwrap":false},"9.9.18":{"name":"micro-kit-atlas","version":"9.9.18","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.9","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.8","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.165","@types/mocha":"^8.0.4","@types/node":"^14.14.10","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.9","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.1","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.0.1","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.2","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.799.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.2","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"6c8d5ec34055dbca09044116ef950f704226e110","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.18","_nodeVersion":"12.20.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-FgHePDQkHHo+A3aZ6QFninPFpsdN8fgAhAauarnyfg4+9fGbSjAZXHg/yZqfDm1zVQC2VrYRwEK+Z9QsgVdW6Q==","shasum":"7ce247055661c4c6a99071d8160d019e52e471f6","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.18.tgz","fileCount":168,"unpackedSize":569328,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfx1X2CRA9TVsSAnZWagAAiXQP/RBSsa6ziH6xqEsqnXlJ\nc/7vBtKy612e3D4GCFIH5pg0oHskbgLijDOWHeqOf0tmdaA7dw8iF3yrETwY\noOy0Z16nI/gvmntj6SJCCsJYu6U3rVD6CiXt2Te8E5FM81iqIvt5M86zo8Ab\nJr2DdRZU87CVvIRAwy0xYMkRxMFn0LzOf02Sn7rxL3tCu25qESdl/Nsmf0wQ\nAWWFslGi8kgcB4uGHXrJQuZZjk0L7+dZHzAgKO6M39WAHLjqi5a8OzeIQcFs\nCAX1gMQSG/lvuP+Bgf7sCrSjagkY4PVYgv2+BA/MKkaqxiGq8C874keqOD/1\nXBBkN16Z9mCgo3k6lRieMuXZ2yZT3GNo2gxQy+DM77S+2kwN/LeQcQWJK8SZ\nuLEJbgyujqBQh0d8GlaWX5QqIpfhFurzYHUeKy8DbUWCOTL1j3cPqLJohm70\nqdsC8vob2t8UX4NRPcF6qESy4Ch2SARvw/bhhlZSHuK/NedDJP6erHpKuJkf\nbfxdBuJl1Rd1iUx3+LmqFXk6JLFcy+1fvON5OFGATbFOEygIcvH+1IVyXZPJ\nonyqUfpVjd3Lsh6pqCtQQeKjnGVmBnMfj3S429QaRbLWD88LtVYytQAybB2f\n4JbmhvrB+sgdoYJUdnxResMUxOLgcKQzfFx6o4/ON3dI0uAix4zCD6FAfpLD\n479r\r\n=6p4o\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDK7xoHkGL78d0Eyzuk56ohyRPyUhbjmNdseWo5Bm3woQIgcJEMgD3oBfrEQueVnhenLxM4Pzv6q1hwzFQ7tfAh0y8="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.18_1606899189821_0.526661251719037"},"_hasShrinkwrap":false},"9.9.19-alpha.1":{"name":"micro-kit-atlas","version":"9.9.19-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.9","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.8","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.165","@types/mocha":"^8.0.4","@types/node":"^14.14.10","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.9","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.1","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.0.1","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.2","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.799.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.2","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"755ade110e371ad87fbdecd6eefd47b8eaf37c6d","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.19-alpha.1","_nodeVersion":"12.20.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-pekzfQzRudLmJ91/gIk8QO2Vw6sw/UzcP7y/JFBBWO8pWUKiwSEyxHG9AQYnrx1RiVVanaPWbthq6X6S+HHdwQ==","shasum":"f2887364e8930827e7e5b69f4da7cc999344f8f2","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.19-alpha.1.tgz","fileCount":168,"unpackedSize":577590,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf0fx6CRA9TVsSAnZWagAALvoQAJbreDfq/ZG4pAJSETho\nfsyUFU/rjoHLIXV22UYdaHHUmiHUqC48JjNowdONmFBFTsvHdak4L56T8cfT\nDSQg+Tsmvbc2FHlxyhlverQTlBJSRQcH4DJcRFxSvwv608JHqczLeohc2/fl\nE4TMlNEQGqW0GCnjxseeado6z+jfsXtv08WLUKYSDdSmfKPWm4WllRtAjl9j\nF2ftwsjFsJhemT7V+u8oFu+Kbd+uUyTCYNnEEUJWoLCJc/8GtjIHc8bRbkeB\n/YLkpvZ9U65oO3J5rJfdnDsXRYUzW562jj0DgWG9De2r6wXY4P5iG8UP027B\nmrssUBNM5lPxI2G2YQO7qEPRLUMCJFAPOx/Xf87x7lthlwySdyuJoo7+OCL1\n9SIuA8gxav7FgJLCe7a7QIfmLzAgrLfDmVvZ9hV1e5nwDSk7szf3e+PqxYnE\nhCyqq01PPgO8HWcFs3lUmTHJdtDfOvlr6i+amJp4IoZWBltaalIOiyqdd42J\nSp5Q8zudrxpZyVxajGg46XLtucrl6cdEjo11RDebEm9cBwRL4lcAxOZq97D3\nqzw9TUNinbIdkUoeq3tMsxWyORrjlS2RlhPl48a9OWcZOeg19lQi8pA9P1H+\naTHzd7Y2YbXl4LFV9e6r09xwssObUwn+CQ/kNpkyARYAkKSrJWvd7/IHyHJx\nOpss\r\n=48nT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGNUedIUVcx2VwJzzoJNha3YVOAA7AGAmY6sf/pyKJP3AiEA8qYetETRACFEDKDIN4VvS9EuL7cxI9oGKCVRa02fnvM="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.19-alpha.1_1607597178120_0.5112993956209384"},"_hasShrinkwrap":false},"9.9.19":{"name":"micro-kit-atlas","version":"9.9.19","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.9","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.8","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.165","@types/mocha":"^8.0.4","@types/node":"^14.14.10","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.9","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.1","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.0.1","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.2","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.799.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.2","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"26b457be022438bab3d32991bf09f7e95ba2b50c","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.19","_nodeVersion":"12.20.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-DUnJ1fGlCpBbBoo8xe9jqGyS8XlaZRnaXsfrCV6Tm4Fat78I0L8zQdFxYVXhx1uyOiJ4aWkDAMlCXgVXp375Vg==","shasum":"6d05b808ffa59fec3e4b9a15199ff88b480d5b25","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.19.tgz","fileCount":168,"unpackedSize":577326,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf0jldCRA9TVsSAnZWagAAYxYP/3Q0wP7qLp66QZUaYJAN\n0hDkpfmGJYiFmdYNcQa5zVgbsYpEzpxu7wiFCH35VqxjBMUa80RlpONlfi2L\nkJ7x1INS7mSOYzNwA41QI97+ym71ml6ZVOL4ep25bbgd22GofaeFCNsOBihC\n6GX0z4oF9y1P791t3TsCxLzzmnvzoyOgeh6l7xJG3mWKki5M+Pl9FT58/KFi\nBNYmXI3fn7a5coQELEqrfwqRrfWAoRXvWHFEqy1wW2Zndwl/HROHYq9q9Flr\nrSymKsEsniLL6eCXfXQmCr9RjvLeQ8sYywqx51AW/Ujlv49TkT8iTqVOKwn3\nOdiPtEP4V7tG+tFQ8MARTyyDl2+4n5qIR9dBd1Zz4v4gjOLQtORZCnnqJ+Qh\nMuQu365Z+3bkAV1ed32ISObSsbHOh3Q9R2OLWWZpXZb2T5APaJMxo02Nm2p7\n4Q1vYTABV8vOnnIiQBhwvzKWwuS3H9x7+sHT5DS6Nnadx93DGIIUhrl/wZZL\nQuQHKahxdjN3m6cbQXk92Qg0ylcYDx6+VpT7M6VgLl5GRvgcZ9S0Yi7LZrWO\n4Qr/EsgpFHHvyMomEB/SZC/bqAQvgBWwmNx3iVRR2psOgG3D+GRXZ6jQJTA8\nfbPn7OwWVh4BSr5uMIEqWPevdbQX6ryocbaAOERiVb0+7Sg5f3Ot7FdEJiE0\n8bQR\r\n=XJPf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCNQpxpcPIaTeZru8R9n/1Anu0bN+S9CYpKYKpNdSitPQIhAKLXfsa35FiluIRrnPEKAjG3hJhRk5sjGSdAxKndUwfd"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.19_1607612764608_0.25670269188043204"},"_hasShrinkwrap":false},"9.9.20":{"name":"micro-kit-atlas","version":"9.9.20","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.9","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.8","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.165","@types/mocha":"^8.0.4","@types/node":"^14.14.10","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.9","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.1","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.0.1","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.2","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.799.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.2","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"4f2c6144ff9a4dacadb53979d4f03e7f4a1760fc","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.20","_nodeVersion":"12.20.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-gfP8mPjEnhO/zrOE+FbwOnDCqzP+iWyFyOVjI9AsGDPb2msikHtkNEklbex9YH8svMshnucQVqFuLoL8kFhWUA==","shasum":"39da5a3431fd65d44103febb78341575b1d47cc7","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.20.tgz","fileCount":168,"unpackedSize":579526,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf2nL7CRA9TVsSAnZWagAAsyIQAILbdR7VLlvZt4Msk2sk\n4FIhv3+J81FrjLuSJU/JWD9xaO0MI5EYEBLgbNXqEI4iMOAiYZSAYuTSPVGw\nmjPJecvSOuraOHejUNoHeKB9K2Wb+/U+1etTCuOIzu8Nl/bfeJ07NrJ8u9OG\nIErPp69VJLLAYeWdQxPzqWn1CzdxPsad+ZG9JndjxxCGPL+PKrFbkHPZOBcr\nV5FDYlPiDeuvrzG2Y0k2igelTzY/ax8V97W8H2TRcX60CEyOfGVJVeV/50lE\n0K6mtmI+KFQQHqOSGJtCj002xRRuh2PDs3slbxZjT2uQbBICoQ1CpwowPq5s\nurwf/44cudL55gB2yvrYFsnvNkwH39KKruAZd51Y2O2DUq2BPlZpo5xH72pp\nRyzkIscE0HWy4cx00uKvq8H9Ys0yrPtbL85Nukikb3zv20Om+pvbx1aqQRul\nAqZuwjKMhuGrUg+DaDtHaEH5l3EGjGlOf7dLRtmW2lcGG5r95wqx8bsS3sKH\nIguGVhsMnRKAaA3LJZLk5Mx4scNLpMe1NiVgB5RE5B/94N5XdYU4Nr8vsCgT\ne6b4XL306Yjgz0tGamyZiHBEOXtNpSB1Gdm4bap+vRI9uWanBlqXyzbgTtiz\nGwoSdLBUlfH8pYnrWvq6KEtSBRiNhPJHSDqpc0CPEfnsEBE/684ubqzmnuoP\nla1c\r\n=wY3w\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC4uFE3ESIk6R+fAi4pxq5F75T4MoO/BbbIJnQ/6OXL+AiASpGf6rZj+DPb9Z2nGzM2YHi6j9tCGXU4cZcfZgIIRLg=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.20_1608151803084_0.12502187152835686"},"_hasShrinkwrap":false},"9.9.21":{"name":"micro-kit-atlas","version":"9.9.21","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.9","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.8","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.165","@types/mocha":"^8.0.4","@types/node":"^14.14.10","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.9","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.1","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.0.1","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.2","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.799.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.2","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"0288dc7b021c47e8250509423f89b9ec4e14ccae","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.21","_nodeVersion":"12.20.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-4t6WHKVaTV08Z3eF+bTrgyGEFdnNXq+colBdavlovl950c6CsiFLnXzkRWVAHofX1jHE47a+2R5+F6IITKWSuA==","shasum":"67a20751ad683d5a035eb098d655ee50ce5d89e2","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.21.tgz","fileCount":168,"unpackedSize":581781,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf4QeSCRA9TVsSAnZWagAAohIP/1Ho9IBP7dNoMgvaaABX\n1lBFMIx9flzhxVVIyapZuwpdcfVxG50rYvxMCoL4NMq4XREzhx1UazPXd4/b\nkMmc/N0WiLBNI1r5FXK+kS39xO4V5N+/qEQKO3NmTLFjGjIc56UhlPmbWr9E\n0H3QQ6F20S5EVGcBoqw3E7Ot9ZOD7f+l4QRBkxvxIKlsb0Os4UYj1dE5tQSI\nlcQqA3q6AreXTb3RQnO90hnZ1mBnzf3w3jWprB7JkYUW/EFG4c+8AgRE7zyD\nQZSXlzC+GVCwJVQRAuvRGEE4hW2XlEAi95cX4jEpfDzunza9CXT+58oxdeEM\n6nuC8/zlHVx7oQ72VQm0D6y7wrILijYKWS2SMYtisu9sjVVXK0JQG7QDSAQ7\nwbxnK6eONMDFcLTHEsLOKGNHRhUUEV42SxfTDBvqQqKGmUNyrEvIXl1rXMo8\nxGH4CyTuhx+ef9/4v+byoLbu7+zZCOuBHXMYDCOr0pM9lwqGjKgGiq0sPdKT\nQgaY1mVqX54+oodESm4A32aRVnYsqT9QwEEngmhjHbnxSJ3jb6KWk/nEZ00E\n05j58etoeOVEvpHWuotVh4ZyKvqGgFJVCkmJGa9k1OM8M/pJAW/aDXw5o1K6\ngrjpsK7wWPbIZqv5FlVc4DyTfXfPESdmhTImm1+7zz/mmK5Hdub8ZJ08D+GB\nX6N0\r\n=TEn0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC1nMlzNzgpFzeuFO554+fruFo1R2V9Ryle8GWn2iqsKAiAaUn6q9wL6bTsd/YJNqTt8/zKx4F5Z9IeA3HnxFT+21Q=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.21_1608583057637_0.5830083892068023"},"_hasShrinkwrap":false},"9.9.22":{"name":"micro-kit-atlas","version":"9.9.22","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.9","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.8","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.165","@types/mocha":"^8.0.4","@types/node":"^14.14.10","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.9","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.1","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.0.1","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.2","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.799.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.2","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"f114924561a6e90332ef05a7175238a66205fa3c","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.22","_nodeVersion":"12.20.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-s5RAfIjqsWmNzWpmIaDmNyMBFlYKwCBrA2qBLslxz6T6PXucXBqvvWXVmsuaPiqB9YpDhma/mn6AXeSaKhpu6w==","shasum":"eb43b9d14299fc3deb39681c55e016ae08c3376a","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.22.tgz","fileCount":168,"unpackedSize":582084,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf4x0SCRA9TVsSAnZWagAA/4AP/ilJFV9WhM3TAE+Kx98J\niQVLEyKxulWTQGxIfjZG2a+pQqOgWWDfyEgV4dRRGvxM1U6PHhWkiHn9+Oh2\nWu0fxUYsY3ev6SCTclvEIp0n83wq8LudRykDVAnDaOKlR0rB70yBaqxg93iR\noUxjRnPguNWZG7zR8l/iwOnh3oB60bGw94VEddzBE2EZ4C8KBqJNTl/k1Fum\nQ6vJSFKKuvt6R/4AzW0VOFFf/MPloHnFWvwk6eJIYHTaG5qctTFnurmxTUuw\n7iw9Q+QkbQxZB2ixCUYWMhgvxF3zo/I4EeRenbXQA0Y/u8M8jxs9KK8MbybC\nsYJUH4ZNy85QWwioP9msNgeXgeMNVQ4Mg2rOjkG/QgdjoKvz58YUnZFZU1jO\n5LLQZaapPyDzl1Z5LLQ/5m/YvDMG4jDhqrV0WUGaJ4W50nVMTBe0hts/RWr+\n/G4krbtnIMN5eK3rNt6kDlmg+Uvp89yRhvuSSXJX3aUVbMKo5Qe7jiAH6Ky1\nJWz3UPyCSOvSIQIYIeXQO6AY/XcgqSN7BgpUMhMIsLTPtA0whJ64XL2c+yQL\nuAOmSCqSZ9bLx6LFkVnkqm4XKTTvhYHGsbk4lMgN+qKDt6nxXhy1Dg8jjiV7\nPP/PN5ZPAU5a5ZEyC8h4kJVbZp5F2qzdMHJ0g4z6UUYzbY+EBZSHMCBb44AY\nlIeL\r\n=5R+h\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDwEKpgiTH3g5L6hi9ezQwH3IEH2qwC1xaw9qoIML2mRAiApku4BmA/EisbBnDtCzwmWmTpL5LunusDvvZ+9QOeMkA=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.22_1608719634255_0.9691892598462863"},"_hasShrinkwrap":false},"9.9.23":{"name":"micro-kit-atlas","version":"9.9.23","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.9","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.8","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.165","@types/mocha":"^8.0.4","@types/node":"^14.14.10","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.9","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.1","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.0.1","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.2","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.799.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.2","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"cd7f0917346b1953936d42b24ed98ba05c101c89","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.23","_nodeVersion":"12.20.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-hslODo7LC+jivIYHVPCgPW89Rz4mviEWllrDgt64NBM6QoK9VW7fx+DYKJ5/nUQjlCVLPtOCodJgyGubbhhXeA==","shasum":"9c14e4e8bbcad0fab8d7645adc596680f5ad116a","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.23.tgz","fileCount":168,"unpackedSize":583440,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf6wRGCRA9TVsSAnZWagAAm9EP/Rsd5KMRm502MOnxE/XZ\nbyj9BbQ5uGsXGU1xwBXlQU50f6K48tJrs3ZNEcwuPaor3HVl1w5j28r0pNKr\ncgabH82hlJUFO/CmHwaD1ICRKSYQyVHWafUhyBdrL7s3W/BOOvrygah6jg4D\n57r4T57ls7SPvDX1BX/ekS+sxXyensS5XrEVTK6RtJxfDtZjEsOjTTT3WvE5\nRt6ke6B551qbs2NtX3ynrXPDnxBfsW9yKPQY2T/ENqmdh/Akvtf3x0uwJ1uZ\nPf6FPTgJw2yyLPlKEmebEE1+GHh4g5slMfeTeETHEfzS8jyAWD37+ORvyQFq\n5fQscHvVUbsf5+tvhoLZEVkxU/EN6eZJXV3oeVfqQDwtAOORsZp7x1OXnqc+\n12h5gawoCRYByGggC28v7tRseqEfO1n1BUOt5AWHyWgdC5X5z6ANXv/w7phx\nf37ApoZbMz6xBwCeVIU2azTKD7SUL1XMCvv1pc99egF7i9SnuvmFVZaGNFdw\nrBAK+uXbSjf2btpw4mPzekUFpQBS8xBtWNqAm/NN8RoKnaP03gwLBKRfQ1hb\nMVxefrtPwU/wgigK5k3GaSB+T45+v98SyoVfTH4vS3a1Oby68PRJ+5Evy15v\nIT2fVYmZ+GAb54Nwdl+ZcbBeLV+ts+9symoLOQLoe4gTjQaLa46f7GDH27CZ\n9XNj\r\n=Pny+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDX8ROvFWclS2vbQss7YZnYEOiv+h2J9BHGHsKnO6U/rAiAv2NU93MYQCiGzurhWB0eaGfJpb4WPMAf8es2+er5pmg=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.23_1609237573589_0.3150848628069587"},"_hasShrinkwrap":false},"9.9.24-alpha.1":{"name":"micro-kit-atlas","version":"9.9.24-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.9","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.8","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.165","@types/mocha":"^8.0.4","@types/node":"^14.14.10","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.9","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.1","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.0.1","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.2","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.799.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.2","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"b36c71ac3232331e13841f8cbb63effa8d0548bf","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.24-alpha.1","_nodeVersion":"12.20.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-POf0QYBdwe2kr7lS4RLlgPlv6dvtXt58YwUwGuY5S4T/tdgp/a7iu9LVxqIwVfYeyHuT5Rqvwor1KcHieSntJQ==","shasum":"39e5843e8198402536290bc293e1ce2f4c27e672","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.24-alpha.1.tgz","fileCount":174,"unpackedSize":587656,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf8u19CRA9TVsSAnZWagAAySIP/3Tn7ZdZZn3KbuDulpHa\nkX1KAfDyZQTJgOwy7YamJuev/4ZNCxP1Tg/sarBorsAW0RqAqtC6JNNuGPu+\nBW+dmLTa3c96U6V59hFq8BWf36NqwoOVqmGrdr+Z/V9aAaJug/3OaC1/VZvw\n2qZQz9wCId+z4Eis5BydDC1g+mAWeXSwXsnvRYfL1RoM+IPTZu8d2rwFZ8gr\nM1bLNXF24rTaBDZdlYnGrnXWaRRaEEngCU4/XpeonBLKSNweNP18Be5F06tw\nbjj+Eai5ymvLPo0Fv3trlWFL4Rd+j8wbEraE4+4DTr6Pyl/0hL6hcRp/tTzj\npxakTe9Leeho3iiS8vN67KPMeGkO7EI8pMIbt4dahxZZN9mzRy+ZwIT8MFav\nU/lrpfybBMMpblUIZJJy18a5pa40cZvT59PHuK0R1uHZ+Qhpw3INAPAsIwb1\nLQgCBv5vIdfnORG64W/cN0uGkB/AjCj12g8BJJjBpVQqAFnn2oOGyc7mWuYe\nAJ2biZK/MGcOi5DoEtJgwmVtEJXCXm42VygfTeWiYiFsX9+XN8kcPlYekVm0\nU916gl2NouacjDSpWG0jJr29hqb6MhgUTQ7SqiRuxVBozjVauzIaIkMzfqqV\nZtxhlyp9C32vg+cdDFnafR+sZLd7I6VE8bkeC7uX5uhE/Jsh4MkrpTCQiEI/\nIlQm\r\n=jFQU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDYi5z/fJeXlfaTXLvUhSnR7BHvSz2H8zMwzqYVq5WH7AIgCsz6OUo4V+Df+KN4MJyKoYJ1FRTCZLBROq07Kpwjzew="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.24-alpha.1_1609756029300_0.9026000578539219"},"_hasShrinkwrap":false},"9.9.24-alpha.2":{"name":"micro-kit-atlas","version":"9.9.24-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.9","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.8","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.165","@types/mocha":"^8.0.4","@types/node":"^14.14.10","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.9","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.1","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.0.1","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.2","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.799.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.2","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"1e0ed16b225df179048c487db7eb98a82923dcd8","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.24-alpha.2","_nodeVersion":"12.20.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-I/zQPCIOTWrw//yCBdbcvbI8EBAUn9Nn06zGGuhmcBZGLou0U+xpuVnojvCG4xF11rfj4vpcvbT4kaix9AanEw==","shasum":"8bed5d8112cb5dd821f5d77e5cf579dab5ac3ed1","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.24-alpha.2.tgz","fileCount":174,"unpackedSize":590263,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf8v5YCRA9TVsSAnZWagAA3GgP/2UCyxcNAqBrcJ74J5/1\nlysCBSKymFRrhdCdSCrwD2/WXHvcpv7FHhv9WrE4meCm0IwZdA/3qlVNAbtA\nP/YKEsCU0ktGo7hPwY8NJgF7zfpzAsuIazp4oS/4SM8Qfj7woJkvKyOZ/YU7\nOfpkAMy9D/00SoEkm5Czai8F5WpTyNq6Hw8AipitxnxxFz53cWixnmKrpyXZ\nB8W1eGLuE6sbdyPa6ubralzBNY3JDwaX9bC1LcMcFcQLBu09Cg/dEXBe8+j/\nDGKMeJXpvRVDuOO4Sul4EZbqK7PLac2xD5ErnajV6zWLnFAQegYcu9Z8z8S9\ng3+176j2zwLcRpOodHx+uTCFlJlMJKGUzyuo6JD/PzhsyoTNVft5ghsPX+LJ\n53HlEjsIrm/JImhWT4uhIHeayYZYHz2zfp4aW1+5r2/6RN2j7Tx3USoTo+9N\nBH5hv07KAEj90UeZ8bMdCisgbfalz07z2Rta/fx0he4KUqgsFVG1z1yNkOnd\nCZQhTr4hcqy6X6tP3P6CuCw+PaDJmDS9WcS8IGRMcQG/IOp97zTrxCegHzJK\nsAU/Cz+JDMop/75nwhdFngx+taEi4h3VW6SOAvWjqEeoxFU8O4PT8BwZ8/io\n3KPdNR4hYsiZTCoCv9VtYqs2wTPvUfN+xx7jWdKQvKpzOLHlxJKRVoxJAbSM\nxDov\r\n=TgPv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC3r+doHZV6mBcnBQVtel5EIDknNVXdwT/O2jaoeBACSwIhAKaL7I9xipQXog/dholZIZLYAnYvtD+dyDP1Al9S63mk"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.24-alpha.2_1609760344087_0.6677831893310338"},"_hasShrinkwrap":false},"9.9.24-alpha.3":{"name":"micro-kit-atlas","version":"9.9.24-alpha.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.9","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.8","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.165","@types/mocha":"^8.0.4","@types/node":"^14.14.10","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.9","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.1","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.0.1","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.2","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.799.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.2","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"535fe1aa5552726f624a163f0e81aba1aaf8363c","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.24-alpha.3","_nodeVersion":"12.20.1","_npmVersion":"6.14.10","dist":{"integrity":"sha512-9EUIEd8ktCh2YMYlmPJaZuSgKiS5C63B9Rh5oN6MiYFgkqtg+j2iqjfncNDwUqlWCoXhl2z7zfMo8shc5NityA==","shasum":"da52edae732cbc4236617374973fca5727278e75","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.24-alpha.3.tgz","fileCount":174,"unpackedSize":591295,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf9YcmCRA9TVsSAnZWagAAFWEP/1wbgXZtpqNQeP9hEuCA\ny4h8XoXGiSXcMh75CDrgkXYMydMqB3fEinQzr24+P+907WLyfTvlXhVi4Oew\nSRIe8IJfxcnd4ODCXAsVS39OeOPwGs/KSOUCOvcSK6SPWnIJ69XZdfGslZzD\nDeTur9OT0dAUyD0ejfgBCmXzGknjWIuClpII/OMBQ+LIjGKBdQ3BYof4vEp4\nPrzGhsJkON/Yg4/yO90NEC4SCDyFyi2hZ7nxCttOIJHDYkv1CJ7DWc+zZ0k9\nddWy/1ufI4J0BkZxOrOdAzvIP8gCIGp/gFSO0gAA+7YIMG32bJzcSM5Epeec\nuYMvSZQ6Uu34InnLuf1eB3prQzMbDO9ADBv6P/BSSq3J18iQqAX6PhxY+l3V\njHxmVA5NVv09hPYXX0rkw9mzvdwwOld7LLt4s6kr5JdggJ6fNTt7nP+Vwvyf\nV55tQGQj9v7jshqVo7FyvAoHHIT19dYyg4tSxrw1AU8K1kijIcFLC49lnyiv\nNluDLfonxnyKdtCCC8TL4OCYWD4qeLn6/0umPHE/ZIAjoqS5uqWrftmNhl1V\n2zCHFTKpzEenbRlFbiZOdXi3AxdWe35T2yl7l+E7LWKk7eF+fq+suz6grNe7\nJhWWdAGbY40LpuQaZyz/cDVFuFxyyfCcdHVw81d+py11v1/u30z3DeN+UhrL\nCift\r\n=VsWs\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD7/oVJE09H0fYYzVHic9Dc7h1pwjIRG2ummuycV4HupAIhAOyOLzFf/enfjZ3mdOzTgoGvlpandhFt4QIJ02axsNOE"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.24-alpha.3_1609926437270_0.714908412812244"},"_hasShrinkwrap":false},"9.9.24-alpha.4":{"name":"micro-kit-atlas","version":"9.9.24-alpha.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.36","@types/express":"^4.17.9","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.8","@types/js-yaml":"^3.12.5","@types/lodash":"^4.14.165","@types/mocha":"^8.0.4","@types/node":"^14.14.10","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.9","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.0","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.2","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.1","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.0.1","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-globalid":"^1.0.16","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.2","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.799.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.0.3","dd-trace":"^0.28.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.1","express":"^4.17.1","hot-shots":"^8.2.0","http-aws-es":"^6.0.0","ioredis":"^4.19.2","js-yaml":"^3.14.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.6.8","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.1.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.1","winston":"^3.3.3"},"gitHead":"9d82d2de74930a32ccc7cef6c0271ff42e3ca6d1","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.24-alpha.4","_nodeVersion":"12.20.1","_npmVersion":"6.14.10","dist":{"integrity":"sha512-Xh+ALcxLtRHkcTyTXKVpqjM6qK/X+9qBHFlxL5wv4AoeQ1/77DGJ2BCkOfScnMV55vFq5M0/0oYcIK5DUAZXpA==","shasum":"7706b806bc4049073ea7a6451322553e0e9135b4","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.24-alpha.4.tgz","fileCount":174,"unpackedSize":592267,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf9YuLCRA9TVsSAnZWagAAxDYP/jZ/8votfs+78d1pbK6F\na8Z98sXgJ/TtET9qxHgXdEaNuCZmZQwcqGHe4TjORiSIjqAFXv83j9JZhnCE\n2SIFX+a2x+BBGx6pliAei23KrE/XCxTqQMbJAz1NNndpWVVmTov43qZISgIi\n3XLbQTiUDaMS4LHiidkUUQlgonV5VDoHb20/q0ObRpzGvMZ2gyCNLa3wT3hS\nimLwVvMhVJlp4AIQzrJ+5SJdVZeZvgl12fTtv57pfoOuOmc4dwnMvSkDe8I6\npfgroKppFYVishqXvWqx2ZFTMelkRCskkR6tpEzdVg7Hm/jye/UcUn0XqPw6\nHoPXQpYX5C5dF8l5SkPl6S12fvVA3lf/6Eo8o6zJ9SNCWc2KtYU4Dd7Xc+iO\nD8HVhR7dgh3vuD31spL/NMoblubJDOLeP8psGahuhFgiZQHdSg/jG1PPO8cw\ne2uKavL+WqVSpI61Lv1w4Pbv9HIBv5K1AHdaZ/8wRCFa18yN0+BQezyvfjeF\nkqw85NJe4+vo5YeCoRAD4NHeiKqhfEZu5lUskNI5UJgHBtZfiaL77t4lB7x9\n+PV42ajeGs8HaGO8Oj5GiVROIRFou5wt2JSRVL8f13fNp3Dr2Qy/vCpHXdMr\nXz5VGzIsmWKUBVoQvr+3nupPhOOL+B0fNQQe2dFUSzLtjKxcy6ztc20FaOd7\n3fqP\r\n=Gw9N\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDd23S63RBqxeyIza0v8yp6t6/B7mZWIFBHfL8NpBRTpwIgc3Kn+vFtf5+MeJfYxbx25sugjdY0ozCsBBChveIi0q0="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.24-alpha.4_1609927562734_0.15203434359816614"},"_hasShrinkwrap":false},"9.9.24-alpha.5":{"name":"micro-kit-atlas","version":"9.9.24-alpha.5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.37","@types/express":"^4.17.9","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.10","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.20","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.2","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.0.1","ts-node":"^9.1.1","tslint":"^6.1.3","tslint-config-globalid":"^1.0.18","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.822.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.1.0","dd-trace":"^0.28.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.3.0","http-aws-es":"^6.0.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"9596a6311a6e9daf149af9565e633284c21e33dc","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.24-alpha.5","_nodeVersion":"12.20.1","_npmVersion":"6.14.10","dist":{"integrity":"sha512-PC2dbIZYucJH4D6k4lAjn55HKN9brNS4nr4lCfoJY8CZn9mrXKqY2qbLN6N89g5duMP7c0D5pz8RiKIa6mgbsA==","shasum":"2fc8b9c7437327bdebc36bf6d312dd88d9e26e45","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.24-alpha.5.tgz","fileCount":174,"unpackedSize":592413,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf9dQtCRA9TVsSAnZWagAA/YMP/0VMQ3HdDKSsz4AS0E/H\nqJFLunG8KigFR0IAWnQSnLWwaZQIRGqoqB1Hdyc7tUr6cnKJRcncN+c0UYXw\nZQiIzeEx28W4qNHlxaU76owfW1vLJhwVoWT7Wqdvbm+5f52mSunNE/jLRGKY\nD0KSxUV/Xj231miBYYOoQtb1oD4LEPGYkciCcio93HcHeKdYYPByJN5+xVFC\njcfGfMHs/OCDgSzCcPaQRcNLelYOzGMdTj0nL9PTXb3Zt2CNhIJ+yLynBT8Z\nh2Jaruh5w7NNRY/GL0Q57UHWMG+evoe/Qv2CxVu/0EkkDMhzH2B3cpIRdvY5\nVf3AxytFhWCI7ko/SraNjv+u3cAWVou/rUVoUfuZTXJSbwyRKa7K4/nW2b4Y\nJvoNmudHFgpazB7kBIqRSY1HEtW3FOGXbm+b3gjtOJkQg8+3yCYdEyvmMvsL\nYeuRKKUsxakqtTpNRuYekmPp1aW5kiejP8Q5GTPnU53rrM6lqugKdM6Y88G3\njV/gNmdGHT2eS5Z1FFcfq+2BxKP4n6zaf0NqVKXbFZg2RFdoJA6lr3h1KqKP\nN6zi0O+ZLxBZlxyClEO4zQLZIL8kWlo8G2X819kb/jql3mgEufbNeEErr0NX\n1E5p/G2NY22t4HPGt8BzHD2j5I3kJrkqAuP7KBXbg5pATClghZ49VmVLbnAg\nLl1u\r\n=N7Cg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCdkLa6DQF250rlKKV5K54ULW35Bnpe/GyvrHpX3Q+mywIgdaaotOLLof8S6BZxyqjvuJmbOjNYUwLAaZXPKCx1d0Y="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.24-alpha.5_1609946157161_0.9969672258979743"},"_hasShrinkwrap":false},"9.9.24-alpha.6":{"name":"micro-kit-atlas","version":"9.9.24-alpha.6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.37","@types/express":"^4.17.9","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.10","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.20","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.2","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.0.1","ts-node":"^9.1.1","tslint":"^6.1.3","tslint-config-globalid":"^1.0.18","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.822.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.1.0","dd-trace":"^0.28.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.3.0","http-aws-es":"^6.0.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"4371b4202261f34655f12c815c627ff308cc0dfe","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassType<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassType<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassType<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassType<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassType<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.24-alpha.6","_nodeVersion":"12.20.1","_npmVersion":"6.14.10","dist":{"integrity":"sha512-s/mWXdDhDDSGFvmwdmhBfmZg/EtEvMvcntHqUGOlbUnBuwB34OuW1oe1CUgvxaxpOO5tjHbooFfAddK/UNw0Mg==","shasum":"a1d769f0d839dc96008767d819252727f6154bfd","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.24-alpha.6.tgz","fileCount":174,"unpackedSize":592481,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf9r6OCRA9TVsSAnZWagAAJ4wP/RIQeugEVMlOLHVdwa71\n5JJAS23++o/BkC7oi3svbGGaJkGEmxxMiHZv8pqsNLZB2KEr1YDekTsq37R7\nqBOaU8L8C9eGrOymE+ni9F5E/5sAJAgeOaegaSGT2T+wRZSE2vSFjaNw6msU\n1nUXh7xc2N3Y98SwsOxyeW8sDXqjTPX0MqLg07amzRFNoCRCNXYnT7rJUUwY\nWJ2R9RCWXhEmWqFlVnxKw4zXj4xvBp9jwlIyNAcUBFaIGADd4B5KzcouAYZK\nAX4eW50PSJzt2rhS+5R4UDPh0w3XFdc9/lvef+mUduz/PncjHKFy8rTzhu6X\nrvs2juP3iqF9RRzw5O0uwXi0kESQ8tlA5bOEvX5afoLZu/RoK/ydHkYaN2ZU\n3jbZ6qjeA5sp+hcTxybwMLR7lMiffiLf4uIgoN3J5MhaTovHgjkKN+FViXtX\nDwMe4pgF+9PVNEgwOVs4h3bzI4OhvMD3vi+SU7BWOIR8eoTVkJHwB6JD8bP5\nzLNqtpH1Mzbl3MPEDlx0DdS5OCcef9OyUM18eauojrisbewWva+VwTGpZQXZ\nx9+yQyhFgCukRHDqMhFpidva9fL0TAktDUsWg5AZmaufmdRVkwwQ4ACLPFKk\nP/2M0623NqxxEhcIkEwyHHWxDeW83aV9J7OFBXpRqK7tfmhWx1bH5KHIPp1e\n1Bz+\r\n=stXb\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICQcngqpJxBYorlcYBWFCWYGxBwy7FQfnJZwxctFzupKAiAxuu/II9kCHYrIHVQw7LXpE7iPGAxZCJs5aXgX3FDxrg=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.24-alpha.6_1610006157770_0.9923898105581541"},"_hasShrinkwrap":false},"9.9.24":{"name":"micro-kit-atlas","version":"9.9.24","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.37","@types/express":"^4.17.9","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.17.10","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.20","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.2","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.2","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.0.1","ts-node":"^9.1.1","tslint":"^6.1.3","tslint-config-globalid":"^1.0.18","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.822.0","bluebird":"^3.7.2","class-transformer":"^0.3.1","class-validator":"^0.12.2","class-validator-jsonschema":"^2.1.0","dd-trace":"^0.28.1","decamelize":"^4.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.3.0","http-aws-es":"^6.0.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.4","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^7.0.1","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"b5c38965ad2f4a39c1971711e0d8851874ee0342","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.24","_nodeVersion":"12.20.1","_npmVersion":"6.14.10","dist":{"integrity":"sha512-puCLAvl/Jnk5shu/ss0PTV2S87oCK1fCDbd7m28U8tFy6Vbzzl+nAcuPNt/eilOUdZzqUYxXmXnuHyQD/Ogu8Q==","shasum":"1a8a7764d8c897195c789671e655bbffc77a8bee","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.24.tgz","fileCount":174,"unpackedSize":592473,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf/EWICRA9TVsSAnZWagAA9CQQAJfjWhNUkSNumVsAQpDc\nRAOoGqR1H1Edrqcp4CssZhP+ZS8wMdy4JR0Xuxp07pn0AmLQ47m4AqeQSE0V\noRd7B6PXR90iz/p5r4wtLXwCfBjQz3xp1HnQk+TE/AXKjugo/Kf77nl381kS\n5mnJcdyXFVe1me3FXDT6i3HLi9OYIIZC2261G4uUKNI5gEplYHg/q9jbwFFY\nDpdodrTGVmAgGcvMUyrpoVJFAVb4tPZVCOS2ephyfVTydFYa+oYL9AloJlNk\nvaxN1neq/wK23HT+gZvYbK5oCeq4Wt6TqeHeHmnH+ihAlzsH4dxakbKof0xs\nNEoF+DpGJ7HD1Bx9mt2/OGtEB66ZHtwxW7QFPrLvSTjCbQGikYcU5R9cIvBy\nDhHXZWpQboJ262p7g74afXSAQ8g3RtARYn+HYfYZlLJLtZdZbzDrQfjnx0g8\n0ZFlD74EjsWoxKxek87j0MA3PImLP9HnRK7qGf2au2rf712O+Ovmob9fZq5K\nlr68n6PP3IF6B6a8sb8HxS8CNxG6GgSICo5H+NzstePKDvs+QSqbejpKVZau\nIEkl93RSqcJ/0OehQWbWhP+caGJVr4CF53nEKEZKcXrV2I33XuR1Y9Y11kRt\n+I6DSTWzyBhXMDpYD+PFkcGfmcnP3ZffNH611bGnpBcNY5unMBuZN9dJ61gA\nsaGM\r\n=JBcW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHEftVz+Zz9gNvhgl8AMr6GkfUue2lmtBWdsb2FoRf5TAiANZvfajjT1yY11heG2hV06XGkv6PxCBdMMoEw424t1Mw=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.24_1610368392207_0.2354216254147954"},"_hasShrinkwrap":false},"9.9.25-alpha.1":{"name":"micro-kit-atlas","version":"9.9.25-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.37","@types/express":"^4.17.11","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","tslint":"^6.1.3","tslint-config-globalid":"^1.0.18","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.828.0","bluebird":"^3.7.2","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.0","dd-trace":"^0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.3.0","http-aws-es":"^6.0.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"f80d3a105bd2742dba9288584aefbd444057dc80","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.25-alpha.1","_nodeVersion":"12.20.1","_npmVersion":"6.14.10","dist":{"integrity":"sha512-2cNiFXwZVxEE2og2eTitXtXPGHU/Tq3mpaHBZX0U9nqTJd3+Z87OaL62R2CuEgbzLBg4JwS6ODlhNiQpIK1gYQ==","shasum":"496ee28211bf2939d289b0e8ce59f44d401fb981","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.25-alpha.1.tgz","fileCount":174,"unpackedSize":600473,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgBX1MCRA9TVsSAnZWagAAKJIQAJj0hdy9PponvHRI6xu4\nOwbdRla4buQIcFeADT5JI0DrqNCsgQB1Y4sLe/hJkHn6+DwkqLNjS0lwgbpP\nxkMqDcHjnxPF141WNGP/4QlvqE4wJKJ632ND89+sMGPjHBP6V06gUrpmyh28\nIoQczFuj6HBb2llOmVi4Caf/OuiPZSiQITMZDyCHrk/smtmaP8kHacBAgoNb\ny9/YZD/HbuKuy4hgCbaIxHhRiGRbhsXph6PyvWY+d9Le2Vwcg1p1NgJB1wfu\nJCr0wMnrgcUMPoi/3V21kZTMD0Qq1W4uYy5oCyoxW081ChOA0YFSazaHOieL\n0GTDW1X9Wbk3/0AzXWRZWEJJ9gRvh/kdsXbqFzi/dBIH84G848SLw0p6ByLk\nXooT+2ME9akKZPu/oRQlri+eSFTIAZU6kRpEXSBs20ifQ+g8O9hXubuPKzOj\nR4L2jG3Ok7Knzz0F5hbBfP2N45juokX62JXZIlOGai3TSse/JnsvpNY1NfP8\nRVBVBQAKu0NJVXJCfCDWzTh0apO9H8d5ad+TdfVr05bR1pm3TrvzNz5zdZPS\nfZJsjT/zV49zAkNHbnhMeh6Nwo5Qy+0idWaD7n3+d0BqUWu6Yl6vlTolJ/Bh\nM3HNHIoecRwjlGR+JJqc7YGN9JwVX1TuloDzOxfA8e/5disqwA2jNn5o4/iF\n6oMT\r\n=kRi+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBIx53zhHWFaIb18ZV9UBwcCauGqJSjebLR/nfuQh27OAiAByK73w3Xu1avvbORXmMNl/++k04IJmDTzn74FXiI6Lw=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.25-alpha.1_1610972491972_0.7838702045993806"},"_hasShrinkwrap":false},"9.9.25":{"name":"micro-kit-atlas","version":"9.9.25","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.37","@types/express":"^4.17.11","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","tslint":"^6.1.3","tslint-config-globalid":"^1.0.18","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.828.0","bluebird":"^3.7.2","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.0","dd-trace":"^0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.3.0","http-aws-es":"^6.0.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"a01b86f025a68a24a1b7cb602896b7dea0652841","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.25","_nodeVersion":"12.20.1","_npmVersion":"6.14.10","dist":{"integrity":"sha512-3FGYGJMpYaI/dV70tz82VuFnBnhIQZjruWYE7pfvaXi5mI6rWd6VlYJUnPekprwuhAfO8nBZGQB76SgRJj9Nng==","shasum":"55904e6b0dff5f07255e4d016dfe1022160a46fd","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.25.tgz","fileCount":174,"unpackedSize":600465,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgBbkACRA9TVsSAnZWagAAqWMP/0t5jFDEeKVTxnBR15Zn\nBAfg1iMLtOfhe+cwpFhlxHu3+lVPTCzmC6n+s1jKzYualOSQxYAcFBrkJRkY\ny48HL+sLLYkO7YTteiu8gmhGkpGhNFgVgqU11Usj3kPYooiqP9O9MCPCre63\n/adrPUNAd2MEFHy5Zhkv960spgkbewRpaRlMwIg7S6YreM2aSc96ECKkGLge\nK9KR55xS5ViwHq+dv/ZS8/h5dbAiP7bzG0TH+rLi2BevMjuvnRa1Gpy1j2Np\nPDCdMkqrGdLIppqfk9DrOPJGvmpTPI6tbInK4W+aXFim2E3yggVHfdeNJEHm\ncXxAjCCbQMQNP8uUA++lbQArhbLQELE4Cmdyw/ta26WegsC81vSCmG/2JE8A\nybggQMkXMHC9efZNjblNHaDZoUwR30QZUdvJdxTjJa88nyXt6fAsF9P3EFiF\nDHcHk5M5NYdjJ/sgW6QxG/iI0X3Jiy3VYp1/NzYJt0ITaTmgc0wvIu3oge9D\nsEomhofZVc2cdwjkXsw0rd+2n6hWUorWq/zFcgmi6Mbej0yJphlYGyCVwciT\nIbqGU4A4TgzhYa8IqGjJRYVBMq6T/xNJ3xEa7ORDUKCi7Imr01t0uQ2xwAex\n/OqvYYL+i5ifCZj2eQjZBvk8VNHuOCYp+oDZ3G5Bqs4F/Rkqaob2t7UGUi/O\nJkIb\r\n=rsU6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDG9K3+8eAGjOtZmd07zJ10yxhRS/YmGQpsLh+GuD4D3AIgTxKQHHViu2bqPrJtsSoBv21/4XThR6Ad1Isuxkiieeg="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.25_1610987776286_0.05641417934362658"},"_hasShrinkwrap":false},"9.9.26-alpha.1":{"name":"micro-kit-atlas","version":"9.9.26-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.37","@types/express":"^4.17.11","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","tslint":"^6.1.3","tslint-config-globalid":"^1.0.18","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.828.0","bluebird":"^3.7.2","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.0","dd-trace":"^0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.3.0","http-aws-es":"^6.0.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"ffd9c0d9497a67c5bdfc88ceafe31ec52a94a7d3","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client\nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n\n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html).\n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.26-alpha.1","_nodeVersion":"12.20.1","_npmVersion":"6.14.10","dist":{"integrity":"sha512-g3TamejkAYzNkNXl1xzqhY6HJG73WQbdWx8XEINdNNd33h4gXhcSxhMGFLaJlXybECXSYIyp1l4AOzMd/PcWfg==","shasum":"f86b8321716f5e8e07fa99dcd99ed001bace74de","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.26-alpha.1.tgz","fileCount":174,"unpackedSize":600827,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgF7uGCRA9TVsSAnZWagAA9msP/0H358dXJnQUwRJ0X+UD\nYoKXKdtilhMQXPjTMFCSBVlEZqgNEg94ZXdxjj6Q8E95VGExT49FKvE2Yr+f\n4/p4oGtQqULpDBxvxvdQ7H6/sgxMxU/ax/7SkMU1iN0UUk3aeJ66BrFG8VHB\n+feqsC3tlcPgB+fBq4EeXRbbeoTl3UsrKf6+sYyhD7uNsf6P2G1uGt4JcW+Z\nUc2tQgdfEQX9UajqMQ0i8rkjd+yFPdqjLIHdnxqrLoXvh6GIIaBsQyTXde7o\nRHQhQg2JN4iCZuJLJ0ZwsiuNJujXBhKwAW7c8BEPbsMCM88saMsh0/2fnA5s\nSfvyWO8X8s+VVIabWk6bmPvG2EwcW6a6uEurr6EclxJHoeX8ZQjjWe1lHa/y\nClRcrVV2XNP1FQpv/qydbqpz3zU1FR76f06qLTQLAYdLmDOJcQD78uHdwHKY\noHurGi+ZkgbDiLVJhx2S2TWPG2WVJE2RRACrEK3l1L/1pkToitSA1bEMLjtG\nEamm886NeaavZ8mAqoQ/qVHWjHH1KYLPiry4RvXrKfjn+lPLmlOcxxXQovsa\nWRrB7GH8VD3nM7esgwC4tYjxwRz3aqd6i1+hKPq740k7kVBRgnHOmIMtKyZ0\nJ4evtb49lECHODk/P1mnL12JvRdBl7txQZHKzm02mCwpq0t51dTDat6ExBSR\nTEJN\r\n=L05d\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHCJ9vjggPZ0aqcJOP73tfBsawRzg5qIomFhRzJl1SOgAiEAxiz96QwWiRsVD9vzrjDTPnobi0+s5KiI+fZNK0622eE="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.26-alpha.1_1612168069916_0.3623800446396994"},"_hasShrinkwrap":false},"9.9.26":{"name":"micro-kit-atlas","version":"9.9.26","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"tslint -p tsconfig.json \"src/**/*.ts\" \"tests/**/*.ts\"","lint-fix":"tslint -p tsconfig.json --fix \"src/**/*.ts\" \"tests/**/*.ts\"","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/elasticsearch":"^5.0.37","@types/express":"^4.17.11","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint-plugin-typescript":"^0.14.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","tslint":"^6.1.3","tslint-config-globalid":"^1.0.18","tslint-config-standard":"^9.0.0","tslint-no-circular-imports":"^0.7.0","typescript":"^4.1.3","typescript-eslint-parser":"^22.0.0","wait-for-expect":"^3.0.2"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"aws-sdk":"^2.828.0","bluebird":"^3.7.2","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.0","dd-trace":"^0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.3.0","http-aws-es":"^6.0.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","request-promise-native":"^1.0.9","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"52f7615ac8c26cbd7c6d39b8c5a655f1c2493d1f","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.26","_nodeVersion":"12.20.1","_npmVersion":"6.14.10","dist":{"integrity":"sha512-9OXoSfpi4fP4iDpr1K2IiWOOZPKhfIeBNADtgK7OEgurmz1RQZVJnHztCsQ0T2XtcpW4+25ivIzglWCHXiEvfA==","shasum":"8eede4a0dc7b374441e8e448d430595b12be021a","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.26.tgz","fileCount":174,"unpackedSize":600819,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgF83fCRA9TVsSAnZWagAA+noP/Rx0jcDfIXJ0I9s6ReLy\n/b+KVQEhXf+OINc5E/84bxv6HixRHDA5PpBRuCknOibiuWgGNdJ1mVqQi+uQ\n42iWZRsXx8wJ4I79ERWa4z8WvbteBQ/VIL9dsZVr0j4QG6MI5zCpw91ha2pg\niN7OANf8kPjWCLYnCy0NuY7eBUrdVZBOUwyEukHwNHqtV8n5x/roTwz2vd1W\nmYIeopcQ7vK2qwlNHLIAasxyOgPkgdWxhLkUEDbbfVE/x/WBAG/ShN4gsHoh\nd8DQfq83nw+yYMYJDchjhVeRNHzy0lqitAAYLuXqPoTmD5RPe8gIbdeBF64W\nsNXvnf9obcdIwSt/SeCRT8N8K53ivVngoBqmmj0ymcF0CeWXB5yUqzOuWV3v\nkZxBsMPq23jwNp0+I523/JIWRCRWcrex/zJhvX6B+5YKrvAhJkghC+zFnb/Q\n3qlDlKIcmlesEmJlp3o6jb4Fl2y5Zvmt1/Wta6I+tzaHxalSMHskGrSrz6Sd\nXaRxSsDqqHuPWiJ/JmkUONPmg7zyx4MG8TShGeTr6kUhmyoe4zRmverhKRii\nqprQ6VtFbgzwtPv8lud6fYi6CIHDQMAAkcIk0o+q+B1BeHT5yidqILRducfX\nJIlQLFxsfIHCmDoPmLYvAUxeE08cXyQ4ctRms/jz0zQkk3DHXOmrbBemzvhx\na17p\r\n=1JZL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICiqrNmWb+UA4brcGWPJ3xG4pPd5vR1iyEV8bO4tAK8hAiEA9JfUb5GO5AV+JSlIWJu6bfk380TPB0Hbx3Hq90Wrj5I="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.26_1612172766635_0.016269519561125767"},"_hasShrinkwrap":false},"9.9.27-alpha.1":{"name":"micro-kit-atlas","version":"9.9.27-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"^0.30.6","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","hot-shots":"^8.3.0","http-aws-es":"^6.0.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"f80835bd34396a2d71d6f393425ab47075730fdd","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.27-alpha.1","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-rpDVFS3nIjTbsM/VrOr8MadtO1NuuZm1mZPu5qdHVc3VxnaN8J3rmktjUl74JvD3k0yfqXwFXWvWcQKJzYZ03g==","shasum":"14baefef8e2b19b19b8eee74aba1d29c6cba2f79","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.27-alpha.1.tgz","fileCount":169,"unpackedSize":1299061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgJWnVCRA9TVsSAnZWagAAl6AP/3cS0FGtJTrlp6NW+Tck\ntQqPGIxKuxAxzfqzsqE7vsx6Dewodh1O4+i6BJofTWmbK9Bi3LuswiJQT8MO\nwxkTWxt4QNnYRFbBCmCdPkgFyiTFJNA+Hx8fuaRYIb9MytDkkk+0hQcgTVwj\niVl/SRDIno/NDNLUx/g2DyhfVR6d/jeMz1o4fVJWI1BFTiqraF/SUaI4UFF9\nXd1jF4L1dFLYVP0tu7tEuM5D9jQ/lgTbaf88LnZoEHb3Kj7zhcURVs2uPY1o\nBsU83YUvEONuel1kqlJ629Jh8+fMr/TYu2IohKDal6MKfvp8yvhFYMd2js7j\nywD2m/6N1O3I9ECute1psZT184lk/kWjUUE5TGWngHjkVWQ4b9HEUSJF4htU\nJsm7y/TjUbIjI+0IrEpA1TiBNfOczF4PnTWKevQrt2678dhes2lmiMD/oz9O\nJMIkXMcM53cSgQciHwDKK214an5hoKpZrxea3RgIPhhqi8NnTjDMzrEZJPgZ\nyhpsM+icznHrdbr8C3t+bDEmINjx+c/kTibytcnTaY6+pMozv/ltXklj6czJ\nYMAEcDbMUmSHAlArTeRogfYoCjfuEJ4x976I/+IKDeEOW6N8iTe8clGwtJ1V\nmPFT7iI9boT5f192wUA6X3u7m5g62SOl6VYHlzuhoNw4g1fhQPzSnVM1eE/b\naHV2\r\n=/aUm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC0ZBTrhmk6Tmr5bF03wtIGo9t+CeqGd05gLvjMmS+mlgIgemMkEaEDwjhKihePgOXjPx8WTQC9lKrw3JvtBex//xA="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.27-alpha.1_1613064661111_0.5617220005804655"},"_hasShrinkwrap":false},"9.9.27-alpha.2":{"name":"micro-kit-atlas","version":"9.9.27-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"^0.30.6","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"9e14745b556324f4fadaa32d4b9b6fabdd1c6604","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.27-alpha.2","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-Br7cRIoXLyTvQ4V5pY2Xi93tqMD6iNlX2UPmnxQ2xmLCs0FR4GPxPdTV7PDAxy0ABGtuUJxvbjV9YT2RoDG3eQ==","shasum":"e6676616e17b8506c10cd8a97eeef4a19717d0b1","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.27-alpha.2.tgz","fileCount":169,"unpackedSize":1299032,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgJrc+CRA9TVsSAnZWagAAr4kP/0jeNPvCSTNK5/lqJTQ4\nBEt5mWYs4ZGftGGca6QHxrBT1w80AtAxN49Skw6VjjxBZe8AyBO0GEakhJZ1\nPkTgbTqfyfHlxz9nLAvYrS1SP31rxj6Z/LRi+07YmEvQPDfRwyi1DQCBNyAH\nD/kmPJdcvBbtUC2gFGh2xjcarKCRY0NpEfEzuMHXCkFzGR16rPsQf/tZXuiD\nj+L9iLOKFKcPfzp9tHHQmYyPWEI+duJOxu1f7NNk1JwLm33Xz0tJV6W8OhBu\nKSf57MWzKNytoXNt5F8HVaRY9DYSjvECzoqhGVauTG6OXRxRbho4YCeVZAF5\njS+lYhLpZRDLNyK1TzM90WWt0R7Uy/8me7q7mzVpziPVfPxLX7GJ0aZHK7KQ\ntl6j4bvaZgZC0lWfiti3TowpjZ7a9qFJGZ1+0wpaLkDYXoFWnhU/5yb+9MJQ\nkFQ9CKP0jE/RwLvX/PfYWfx5WK7G1RRDeM/nK7m+n9s+mrjE1E24uPh+kcPu\n3Ln5Qr1vEoxlUJu8iOOhoyA8i91RaKjywgWyaFVTo9xBPhRuimW7lT0yM0Aq\n1cHkY7QWuBJIc1kSKzo2emlfJflDWTxrP1mnqLHEZtub67+KMJ0rIdaz1CYV\nmFbeZPX4Ptj4blbSsSHe8aFbLQ06w/PAhejNfxBooUO/F9T54/2VMGaFewsA\nLUQi\r\n=Hr3W\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCvq2h46scwNswIkUB+fUpP+RhfHixiAqLpzJVRlBIP/wIhAJlvVY6ZRRSdLnx3ClrzlJvi2mtrfvbJYQr6qyTOv+Hu"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.27-alpha.2_1613150013648_0.4484854875290212"},"_hasShrinkwrap":false},"9.9.27":{"name":"micro-kit-atlas","version":"9.9.27","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"^0.30.6","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"9e14745b556324f4fadaa32d4b9b6fabdd1c6604","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.27","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-ejTg/pwtwqa3YieM9sADpxbks/kpij+je67fHTQF3CH+xRMPkCWwEOo+KjxhazCM+3mlym1dULfEYTdcJLi/hA==","shasum":"8277d0e5a991916bf5143f1865d977e401d9b6a7","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.27.tgz","fileCount":169,"unpackedSize":1299024,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgKorwCRA9TVsSAnZWagAAXJUQAJbcxGePpe31RJvzCEir\n+aKCyEpAx3DkRQk7ZImFmZRp0nzUtYsFfEVB8l5WI+gyZ1hgDNXEwjfi8mSd\nbGJNow609vLwafXtPIcVtdno0Z5SGoIfMqL3gesvVcBe3+1Pp6gy4quZ+rky\nOjOddjgwMyg1S4HcrKN+FhefKz0g0KJBPlWQjoeu5OqyF3Q6NXfVkXgydZdh\n71jCGf+zsqT1N8ThcImlzQehyj+CZXiAxuhXGMdGgLlBeNaGX1t9pURXeLXH\nNv6fAPAD43Ea9u7Drym15M+dN5G7XDNkTCv68GVOe5DSTl2vBLYNkEXq2EfH\nZ4WB1RrubjMqrQBSWOepyQD6L87ylEUEL3j6Ry1FZ3VzFLgHCA79dTzp7BMz\nxOYS+jkAhekkDYVYy1SJvorUg3PaEZbVrQQXzQsoo2DscC7htPU1u9G/qzf3\nANA4teRURlQ4YOfsMnColWHHpnwOq8B/Cvw+fGhHNS5j0hF7YJAQGTsueTiY\nl7+NY3Njw21obIkRqh9TDp7LbR+efRwIIoi5Pr6CeAwph1CMymrEah+vJHEl\nyMMpNyK2gXvf2UnoVV8Y4Eu0V5jmBHyreXz5Z9WYdqyvJGxIGcZ5QeHBXH7/\nn2C/MHog8UJ5A+RsLdkrA3WFYKoJvGaBUCbl+cwUxGV0V4pHS+ArhJ+ZYno4\nZ28D\r\n=uaHz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC46vY1xshO+YIm+ICJ1LoRYr6TFHHut8e0JncuUdRCOgIgTYP1hM6Ng1TCDuBEKldgRRiMbeyYZJPZV+jHBjiEx8A="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.27_1613400815905_0.6102911977527923"},"_hasShrinkwrap":false},"9.9.28":{"name":"micro-kit-atlas","version":"9.9.28","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"^0.30.6","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"d5f508eb8a0abaa02fab395f021dad9ab66356b5","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.28","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-YO35yWQ8BYMyeT6b+cP2/C3IWfRX36f0bqO27TOifiSRt20ifIKyeDZIkaBQ6np80mxCERh/EkkgN6oe3waPhQ==","shasum":"e6207bf8ff363fd16d2234935d870f835766600b","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.28.tgz","fileCount":169,"unpackedSize":1298905,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgL4QbCRA9TVsSAnZWagAAXNwP/0vFYb6k13+OdW/z5sHY\nTMM48VsBFQRgJSsFQrPmPMAfyCOCM3JJq+l1F5jQVFqOfoXRib6K0CB/E13q\n3fkK9YjZko5cqF1ZruOTUVhV4Jr/B5Ktuqx55IEjeu38r/zlGuLK/oeMlAT1\nfY9fBjldSdKv8o52xl3AIkG+aREBja4DVEF4vhx5GULyWM4fNFeZEWoPP+uP\n/SQL+bSBU9yeZKAMb9PXO4qTStv6O9skMiKV0IdH1fcw95mUpnq2HjblzqpM\nsYFKgRGS5j29GuHNVFkY1RgccFPkdqmg0MUgv+UHrOTkhn6S9wCyTf0gVhQg\n3+uixuj9Hdo86IKnWla26RY/slUiYd9biLi7lNFf0IRni7eQGYbw2pAagdwY\ndakrmu1pEf9KyyoArniS1nJSqReX21cb+RQqZZYF/25Nvwt74B6MQWg7CeVm\nSQAiTxIDByV2zIk3kLOpX1/FIkBUjEL6xsdYGHZQ6LlZfeJXeARyYowN6lGy\nEfEnX6Tci2iY+RHrhkOwGUXtmBC70CopaP2FT3lroQ3MraAHgwpujHDfopIJ\nm8Nw8LaGCbafRUZjCa1zyzXKOIpPX5RpkHMOQsQUbLMnm9h/7iKFyHp+CXD+\nJgpiJscuvizCNAX4ma/whVNTERzjLqyI/bYga0wy5SBHsIqegSOwxBOYiX7N\ntvDi\r\n=sD0l\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD8cvKt9CXoyYc2KcqCld8lufYyZTzqp4TrMShti0yWDQIgHtr+7aFHp5ll2FNzhunKuwP29LStLHoxtz2EgJ2c33A="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.28_1613726746344_0.25608838989044624"},"_hasShrinkwrap":false},"9.10.0-alpha.1":{"name":"micro-kit-atlas","version":"9.10.0-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"^0.30.6","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"36d8fcd3676675f5f531b9a84776b693f6e29944","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](#routing-configuration).\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _required_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.10.0-alpha.1","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-p4m9fzIEf2a0BEGH6psM+Xf+zzsGnyYga4P5Yf7cn0VWrRSw0WTzfUjnQ/xljDlr43U75+eqCmbmag8f5EcGJA==","shasum":"4f378dc70cc7ae1cc590db467e871719bf994fa8","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.0-alpha.1.tgz","fileCount":178,"unpackedSize":1309692,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgNN+aCRA9TVsSAnZWagAAPTwP/RdQ7wIWscmjrPXIe4Bt\nPS47yz4eeioeH3ND6NZ26y2YcmhElK/rBM1xKcGVY3e+Hg6LE0coamK2NFSE\n0Jp9o9KbifIrbkh4MEAsMCEL+ZHWS3LCiEdW5nCa1mfQzmLl8ZkFY+LASZpA\nE89orna/xuwvA/tbqVyjI4KYNdRvzVqBSWpb76bCGpYMT0glNGdNDPg1+KZZ\nJPGy1rEor/xCSlsbrpKOnySNoEUGj8IdhL5Ijb+JymFdHNMNqPicu1NI1THT\nqGluE+qBhiyRbWofSilWRKs7FrTEVL/Y3W5LGsRHn1SbVsfx0jp39/7GwQg0\ntjzMbXGVLViWxk7n5EVxu/+rCaPbofejCcucVHKxhtnee/9XM+3iKXnHVaFa\nyRHDg8RbpfladYfSYwOFDQS/LD28UpGDGIU1ufm/5K6N+NP+khx5WpY9Dew8\nUui5P+sftOsiUWnxuNccoMhTaUY5Nh+7xX+FSRzpQPqAPDZXl4itK3/l1yHD\nGqbVgdgCBE2idlWmiISSp1k17obnRv0SGeHjLooBR8WhEGjVdzRgtNGhwaY1\nHgq78LsAKQN+cHHC9VgRME3vloGi+1QfTJzYuUn2ldU9m2p+vCv3DPvCeDvr\nHt+V/OctrIf7f6xws8KR+0KS6gQBKFFQQXxSR7rnrNuCEZ1QARF58s0+ieOa\nyviw\r\n=s5Vk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCi3ZXN9YJG6bzIk1iXS/uS4LKyPMOFIAnz7aiBEW8iJgIgOvLNxrny7CYZl/o4k7VLS6N7hriEB6aewBAkMrdb9MM="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.0-alpha.1_1614077850068_0.7663224235402326"},"_hasShrinkwrap":false},"9.9.29-alpha.1":{"name":"micro-kit-atlas","version":"9.9.29-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"^0.30.6","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"26a89f12436e82d2f3f8ccb151fa33bc2344719c","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.29-alpha.1","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-2PsCWIpH4q1DJKPknY/ee+Jst7OF+5ErBN2mVPy0hO062/tGAIvfMSmV9QEoFd0IiQdFzjmN6gDtdB1XqDek3w==","shasum":"ab8509f2853cf551d42908e1981aee493dafdc36","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.29-alpha.1.tgz","fileCount":169,"unpackedSize":1299015,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgNOIHCRA9TVsSAnZWagAA6HEQAJhzh+oZwvHgBV2eYTnu\nlZaViJTqvbzMcaiK5oj3tr++h5HNuJkhNsr0NBY9aFOGpLyu1Iwjwtb724T+\nv3FFlwlUpEtec0DJzM5mL/chFmu52gZr5kSNZIUeXRN8vudMWUeQPhEvMbAv\njqbhMJvADsyKciitFFjLDZEwC8i/6Hy5UwqWTWk1YQA2J6M+ruY34F7UxLUN\n+pNYNrXAp/r1UmkdECD5VqLJwOBdAQtXfatGbLuacp/x503FRVs6UsoL9U1S\n69RHukmVKvd0Lm8xoxR2V2VEW9UdSOGXiYZzpycwFTDZICQlbuMAN/bGhKWo\n/ICHEzCaTkEQXlWY73GxS1C/mBTItTh4j5rjqRvGpG5VJRXoQv9RpeJ57hgs\nDWmIqKQuwh5EnFZeGz2RmDe/7PM5rP8KNzik7r2cZcCmRPcHuU2MV6Ea3uQo\nRHr94rwyydVTRhivAIC5T/QJ5BNKiFky1Ilx19XbtkJNM+uidnhx+/4BmV1q\ne9Xm2G9/57Icw8mQWLMveTNoSVurzavjQaiyC8sZgzAQsiONHn1jQXvNIXUG\n1perLQc6KFHJbjvImipZ6KjzsLBpgqsl0H9ZmEo5Ys/QVygomDuVynt13nOE\nIUrtlqKt5HtDzD7uKkJiXWW/EX9hfShx2rXPalESVFXpoSVBT7+F39LoFCfg\nwW7q\r\n=+04k\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC3evEmn7bT3sFWvghlua+hlRZe491z5w4e/gR3Wi+3ZAiBGyRZsmbyP5oQMZMk09vZ0nJvgbZeRcrF2A1TWsfRQVQ=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.29-alpha.1_1614078470712_0.1028425343840309"},"_hasShrinkwrap":false},"9.10.0-alpha.2":{"name":"micro-kit-atlas","version":"9.10.0-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"^0.30.6","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"461a533cad76503bc074673ca132224e9a2e1b52","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](#routing-configuration).\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _required_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.10.0-alpha.2","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-JgjckQgPMXceU01j0/Pgd3Fy6AIILxThXmzfNe+ZweVHjyKdFRwPjkyGLJGqeMlm586RdXcL1ikQS07qUQocuQ==","shasum":"147e64d366a6b171fcd3cae0d88bfa2f48059496","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.0-alpha.2.tgz","fileCount":178,"unpackedSize":1310842,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgNl9ZCRA9TVsSAnZWagAAuxQP/1SX9Ryx1Nq9EaslZCmT\nvlRZeIYs2L2gEfq337MUSNkZDhXrJd/5YRdkhlmc6agatIKU6b9RcD7YitE8\ndzu7hDDvOjhF3G7rZPAjd0bfz45zrouHQNcgSJL7OB84Q9TV/z/0K5yZgRjw\nfCU8jt/ZjFqjqMnFPSPVx47D1gq1xIaYzLwYgYYw01kE32mSpzA+CAt9OaLR\nbC4V6IldahBfGmvRHjwlQ5Qsd0QALuoYja0UWKYB4nsosEAO4QrlEvtNk/Lk\nT6kbIylVz2Qum3DXJRb8ttKFLMkaJsZBP1Yg78NuyEgGp8wu0mm0hcMsGGt5\n/x3eAnJ3N4dcTFu1cQqOE7xl49Gc7Br1XzXyOX9gB8RN0nVZMNw/LcWrFoiJ\nqJ/yVdz10cQysD7qb/RjbeWUeHbnVI64NpLihSKYUhiYz5tFVmjGu5TJfKlZ\nZXtTkIMbTR7xOrL7VcOClFL6va7joo839yNR0MdCeeY7RWL9cPSgLshF7BXI\ny9smy+Z0J1nYT+wkFx7Q4H0ejMlAuDcOwa62YpMGOU2H9Ym+jPuAyS5O6nlS\n8qYZwpVLpahYN8gDxETXhh7qsvlvRwdLPI6Gu9cZzjIqWiR16CFz79vsEbjp\n+xPo2CV51d6dlDprmQIQ6CAupKSRu5bqmnXRndf+DMWDk15P88PWOsO6HiKm\nGWw4\r\n=Porx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC1opUiXXvZYrDlsxRakpHf3oBF+hUYsz7STIXjX2DdBAIhAK9rGY+A+i/zOkP7S69qc+onC1eOPXxhpoxxEWJ3DtDY"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.0-alpha.2_1614176088333_0.6556547164188582"},"_hasShrinkwrap":false},"9.10.0-alpha.3":{"name":"micro-kit-atlas","version":"9.10.0-alpha.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"^0.30.6","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"f19ab2ca0b6ffeb5150864f13cd24bfd7efec462","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](#routing-configuration).\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _required_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.10.0-alpha.3","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-COH0F2R9yzF45XfjZxTnJM38NTCzOGbanDiYcDafk9gCPCg9WmJoiuk46Zl5JVaAahWb91Pzu3ojHQ9zcFutfw==","shasum":"51008df654b405a95096da65656621968e11ce2a","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.0-alpha.3.tgz","fileCount":178,"unpackedSize":1311832,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgNoMeCRA9TVsSAnZWagAAaNcP/jDH6y9IRLqCeob8XBr1\n+S06xf2SJOvJV/JWNxiK6YwwtfYlzFiItj3QFL2QTR0Hi7JtbEhxPyViaUZ+\nqCm3KHokTzGWaYLesO9bTz0ufQSULeigiQk/eRJd2bpnuDkivaT1keL8FNjL\nUXhubPtwj6AQwUAh+6prgjV3TFrC1/FYEu3AkcbOVfaVwp6Hh2WOwV52Kbhs\n9EDpgZ9E/uQMCNY+cp087CN0MWNAv7v1bbRNRKT81TzfNXt82cHhrLCAiflM\n5h5Ksg5c0ghZI61HpJ7nLxgnVh1XE7zC30U70dLywdDQmY8mov6tP9Lh2TK7\nd4pVopKAyJiOluz0VgMcD12hAca8hpi6k05QDNF4YJQCS7qT45DifpUyECNV\nBrKVWQ0DTTY+Gr9XNYtyI1KIfmaCQXx/8HHV7c3i+yCrVQ0EcC4q8aNrlT7Z\nwHHUo0MvWIm1flXHQN9BbdFpcJg/xnTPShSr31vQJVDPVTmkbnnThfvuMVJU\n3aO5Er0vXXfEOcDb1xOTl56IztWiz+wwzvnmkIZv/pwD0wBpcJALvy8nEsMa\nf9mjotfZYq+XR5rkTUAFQLDrRD4ZIuxIyYybi5LV7R9Cz8k3XQn6wWxQzemq\n/qUcXxCxFzsiqkQ6TU86xCHKwu6RgLrwWpUy9s4Tz0EoE8e8eA728H3Luk1y\niHHw\r\n=Qr+X\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCKxnR9gzgrGWp88xmk6nj0d7v1HxG4RF1spFAnMFkfFAIgTFJQkVQ66v3C/R9+ui2pXCIlAmoDGeOPMJsu2xu54gE="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.0-alpha.3_1614185245776_0.379186691040323"},"_hasShrinkwrap":false},"9.9.29-alpha.2":{"name":"micro-kit-atlas","version":"9.9.29-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"^0.30.6","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"df08b43284fa7211762d284008a151f420ac463e","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.29-alpha.2","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-dw77NPiQyzu/dCPCFfzzxC2ExyjEiAiYh9VXVEFUtHBpXxDudv7Es33X+KDkwtQbpc1DiudBBDagi8MlRMYbZw==","shasum":"28a6405f04a3e7937e563fab9b0dc8180cb897ee","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.29-alpha.2.tgz","fileCount":169,"unpackedSize":1299934,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgN3q0CRA9TVsSAnZWagAAEG4P/3gDxILdCjbXtkVTDJvc\ncCnbLXbLUHU1lWC0ibnUteevs55JBbamndfqBmPLfI8rnYYx64mXkvfu2l3Y\nQmdZ/qCRVnuBpcPqHJt8MPfSqvaMq18Pu2D8Ni4fZF+zTaw9YGECx4xIz+DL\nM9+a0xMXAnlgO5zCIPl/McAkUEzqTUvHCeODwannqyD1gSWDUUr/V6Ux8OIp\nMEF8SPqqmNw8ATHBnYHB1ZyiCj/0Hq4AQOwtv2YFoWDdoWcaI0eIiqPAem19\nd9uDGNhf+AMCgVNbSl8TjJGPTgQmUwZAaRi/FpG9PiTfi8uReny4/cRb3QO1\njDmkn043o2zhmnhQtxpH+gIg5CFhqKt1gp+ZFVU5Q930jF4SfxhujHxo8cX8\no230zIqffM2lFK2lhAQsD9HZ2v1D6GA4bEvSjZngXbtaSYglIlP5T4zTnLKR\nhaMsraGBtgsguPedk5Wbf3KstX47BQFz2aXnyhov3i1wTnNzYzErJnTaj+QH\nhP0Aj3zWYmIJE7plkewK/cDorBJX7qR1HN13iYVnbWVOK0uqmoKsXOFSa89l\nyvqZyDkerqUtR44LEdwRG+JMG/DfvlOYaLXHJ26ZaF4ehIRScWeseXMFD2aD\n2NfeOR9Jje3ntpOlx+y5vgdtPAMn2xg1mLq5uZzSziwb6gSO/86BDMZLRs67\nqHcs\r\n=HRbu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDDLsWVtIhPuzU3tAwuNQA/Ya4FOBwOxU0ZZYadsXG1aAiBrLklOusOPulB30F0sLDVrKioDlTY934wE1U0GEhwTaQ=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.29-alpha.2_1614248627542_0.02501382352517112"},"_hasShrinkwrap":false},"9.9.29":{"name":"micro-kit-atlas","version":"9.9.29","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"^0.30.6","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"df08b43284fa7211762d284008a151f420ac463e","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.29","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-IqL4t3dqyrok9nWMDTJGyQmbgqwPE1+GNue0qp0o0xX+R3QqcCv6TQ5qHY9RorAAIf6WErxSBfaQtgUaLSlPuQ==","shasum":"97b3c0fca3eeb6fb98e95c26f903420d007cb22c","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.29.tgz","fileCount":169,"unpackedSize":1299926,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgN5RkCRA9TVsSAnZWagAAtwAP/2tn6E/LlcpqC4p3ah6z\n0YLNDWnUpwJqRRiad3Oi5dDx3TWax6cpO2vEr5Ow6R+b7qGObcKN5vzTNSjR\nkuLF+MZcqOXXEIpXnaPmTOsqBWl59msZqUHqpBOijPYtPFNfYO1gmv1wyRkK\nBdCcmws4KnX60WseflYw/vW8U7ogO+cXQkGrbTMybV+HgD5IGm7G1pAqogwh\nfqy6xZNJxkzZrEvHa3XhNqRxcQ3ddfquou8iqJKauUV6r3XZLjiC4pL4MwRo\nPNFA+FoEAznSm/VzA4HRHNqldQCajdBGRer43JOJ5hjSt0JuimtkIIycuet5\ns9IO7HkB9qKqoBiWUVYlUqbF+rUCseD9YQqOMHhN4EwhFzi/N3jCR3q/YS9R\neApIOfi7vx0t7rBia9i9d3MU7TiAVqvIgyWJZTjPEgsmH7WkFPLgG1oDx7bW\nxqbNyguRly7DTv7hu1orBVz9akiiWuWovZvVU6oU0pAwG9GllzNgsF2YgBAC\nV72IarmvyzGdXyM14uE7HDWqK0P1ivq+dAAp/q6Um7u/OXc3omKRuN+ZLlPm\niZj2IqtW2VoQOuYc5HPV4gxPFcK9Tr9zh95JnBdCoVNDY3p29QndRCXFuXIa\n1iVqTfu2K4DpP3aHakmszkmSIl3rFLtJlJc1UE5iBGqNEWEJhjOos9MAS6+7\ntYT7\r\n=NlVJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDHtCsHhYbip9uXVdlp9F+TVjC2K7aqhHqHbnawWsON9QIgHtQzfcRedyPPnh8U2OUwpIAgn4IyL/t+KBtrSI3xHT0="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.29_1614255201220_0.3420941072399486"},"_hasShrinkwrap":false},"9.10.0-alpha.4":{"name":"micro-kit-atlas","version":"9.10.0-alpha.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"^0.30.6","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"48d95e5651377da80615573fa7b941419a304c35","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](#routing-configuration).\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _required_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.10.0-alpha.4","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-9Qtcc4vdRzByjcvTWaqPZH93TTMXqKTeBygP3JOXeTCq08R1FMQfOGgJod152hvXPTn1heED0OrCyPlOOx8crg==","shasum":"5e140dbda5f831839eb9157340a0070fa8d7ed67","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.0-alpha.4.tgz","fileCount":178,"unpackedSize":1312853,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgN6FGCRA9TVsSAnZWagAAW74QAJSsdAGwBjMLQCUtdjck\ncrwyfZZWqESSExMRN+UBamiZBuq+D1xJjS1rAsn+nDaQHxJo2uybsMBst1vR\nCUn6GafxiG4I/KmG2onWR9gAbsar0JVF4Cbb/3RUqf7n1hPcZuUlZKhDbJlz\nbgfE+texivp4JR6N0/Qy2N2l9apo07uQS+rRbDFa4UYkDjdrIRlRJmLQk/9J\nUmKkGft2eMPTVxJzXc5XvAN3pRUmlTsx0CdR0bK2u3giaCLtgRVZCwaVnyH6\nRXmFJBmXA8FonDiKw4Q5rfgEoJhC+Kk+alKpaB/sJtpJspar2GvqnaMKWgbd\nZpGX9a+yAvjd7nRxqqrJljNQL5yQIHbs7NQKfy/nPiBbz/tyvUoIBONhYjvp\nwhleeVKMjsV3O52PnAAe7izN98hnI2VfbnGeRYQQ3oX72p5iYR1o9rQlDr4W\nblmQy6uW7TgHpRZORtqXFoMH5ASY1/bEOHy3AL6JYOhpk9T9PM+F18Fvt3CA\nbsAWPXtaCuKM33uoxZ4DeMzRGfP04v/feD6ZRcRD3sIZPCspKP7OVRwyt1wr\n4HPMNiFUPr9LtN3zx7UeUbdbXdTOFWFdgBdOB7xwPJ+NGxmRjmReH/R1xk53\nu5UZFpb5Mjk8v5Q0KZ4e8VgUScmwasLExWKrOntVCFQ3Lk9EINZxWWlCR/Jn\nqZj+\r\n=vLUH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDOXQr3W4+56WZmody9Jhh/KUlimuILsyGGoqi1NfypMgIgdWBzQ6OpUaJm6jdKFMPvQw80cenBi+Odux+QIMm67/8="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.0-alpha.4_1614258501738_0.45202062469968607"},"_hasShrinkwrap":false},"9.9.30-alpha.2":{"name":"micro-kit-atlas","version":"9.9.30-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"^0.30.6","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"d49b83580a644d777ff043fbd33d694368d7ed0d","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.30-alpha.2","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-cQGnYfa+gSmy0jfs7oCtABSH52Jmo46dmCyTk8LF2cxgMNg6VUUKF3z4lA3cF7B5fKwEFnfvpeehXe1URFdQgA==","shasum":"b1c7b4c04b9ef5fa9899bc760a8ac2435bd1339d","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.30-alpha.2.tgz","fileCount":169,"unpackedSize":1300642,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgOPkFCRA9TVsSAnZWagAACDoP/jrlzNBPniynkYaK4git\njAoEKmLbyg/4cLg/4VY7wYC/CGzGNxpU4NhNrOj87NVVNqsrAA+tTLMwnsFs\nVi2YvDktOquLdFGXRftYuxyTebJ+6ONdA7rPugfjUyqtV4dv5tvnz1Rw90Qo\nTEZr2Rs1X1ZpV+2u5syxMqaQ1WRxi52Mpr02N7TdhPZEKzY7rEZ3gCDON3ef\nPWEhHQkYoBeyhJPNloksSUf69P9aXduG0W8uBE+pBR9wRZBROW54c32bQScn\ni5G8mCrRjcFwa2Un/FQG+t0fZP6YX5dXmM467Tn6L+ojbemSKaClZRhIQExt\nAf+fSvQkQBZvFZeHWZ/H703FL4UMeB7TmBWhdtDIaLJVXldBaMSSTtGJsZoa\ncMRI0BCEDveMX3uabpEPp39IvzNHDzBtGN//cOMtAkFKvc+X60mWMEZYVhxf\nzjGn3DOErxwkIgTpqGkA8oqKRlqqcpXPQGXc/jg+IzQWNSQUFPPcJtv4uwex\nwizS3+Lk0PL2r76g7itIUgtYJ+yzufW+B7VJxOnjyv5ZXZKB342WMgJ4SKQt\nSrc+DIgXFFsFDq7//K81oZKcJVR0ljDa20Kp9ICLYMYuJA+6vZg+EV2c28mV\npQs/SUiLRKlXwEP1TLUSKcqv+gP9XLlG+aD42bWetcxs8JZPxsvmE6IboTiQ\ntLqA\r\n=N9p2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBRvCnndPvIF5e+NFE2kQwWbDrnk+8E+zXgwDfli4IxpAiEA7MTvTgXVRwLIZr6CL7pebU24qU72tt27TnWO61ZwVtE="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.30-alpha.2_1614346500629_0.6952629970814985"},"_hasShrinkwrap":false},"9.9.30-alpha.3":{"name":"micro-kit-atlas","version":"9.9.30-alpha.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"^0.30.6","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"a681bd8fda32f85c6714d69ab2cde559c2b4fd89","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected.\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See RoutingConfig.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes have a middleware check that the request has hit the API with `x-token-data` header set. A request without the header will be met with a 401 Unauthorised response. If token data is required in the handler `@TokenDataParam() tokenData: TokenData` parameter should be added. If this parameter is added validation is also performed on the `x-token-data` header data.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<string> {\n        return tokenData.uuid\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v1/my-uuid`. You'll have tu set the `x-token-data` header.\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams and TokenProtectedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.30-alpha.3","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-MpkTrYBy0zBoFC9lWMT9SLcMjmB6gm6YuuHIalnb7zqEut/xXKVNEV5vjdXJXY6uf4hNo5O99quo6duYSu6DpQ==","shasum":"6719bcef79437be5d5b917cffeca23391c52ad24","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.30-alpha.3.tgz","fileCount":169,"unpackedSize":1300632,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgPKhHCRA9TVsSAnZWagAAOAYP/1qqr8bIo3JXB9pPWy7D\n3reqefinAgfonsUGRNU+eN0o+VwpOZhVEexU+Z7mc+lJqkuB64v7dKr1+AtJ\nCMyZUEABDsVbgGoWkCFyC7FSyWnoEIjYAQhAJfTKIYuKd0O6HgBlpG3A+SSM\ndwcwohF5jHSmRRWJwts6u1OoKLe8cc7nTEoFDSazvNf/pvapou1YF5t2Cu/U\nDmga9tHw1Rh6pqsZq5OctocyG19D8X+5VPuZaFVz/fKw2vOhkWmJn95d5Qke\n/Q9yjPp46JcU+31R1rUrSbUmtF+w2TKViAqshax6RZBv94DMC+5fu+Vys2iH\nJB9FxCiBdOFR1OI3AXqx4aNAr5e4UYzoVYZSZi2hTfK2GbeB7TD0++4F4yc4\nYW0vaI1RwRgazLHxEUPgmWFTOY5AhFp6Qw7Fwp/aISnoIcuVZhSpf/mI2Hve\nUzqhxfXZ9EKQmjCnPujf2ovWI2eBxjaL7SjADjJu1e5tJHmHuUBMPeDFM1OS\n3AnyEufT4BLXFTXYW+dLFtiQOU6tUQTKdRudmV2WFsU5rlJsTDS9ANqA3Ox+\nnUVyxmBq12Tbjzrj5Kacuilw0wA+iJGohKQf2+P9fDBzJljhQjijLob8zY3x\nGBJqxQHXcGErRKts86aTuJWt4oAr1OJ/PlGEsXtjgXfdv9O75PBNbWe5vtYI\nacx5\r\n=vbM4\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDec0oQhu+A8p+1J8p9W1tkgB2B6vpo4+LI5iElLT8iRgIhALEVGKWOt3Ts3oLQb+q56Gsom6fDYJJJTcegfHj+6awb"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.30-alpha.3_1614587975074_0.64537397908518"},"_hasShrinkwrap":false},"9.9.30":{"name":"micro-kit-atlas","version":"9.9.30","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"^0.30.6","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"b2365cad286d7f01ef47707dd1e14ccf77bab837","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.30","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-dZE0veWK+lXRIIke5NGMHEaTzIIRo0tkK9yC+o4Hmt1nDNCHsdmJM3g5K3maatDJCbvJsZABCnOVZnq7Me2Lww==","shasum":"6dd322d1529ecabfc76cceb38657545cd7b8225d","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.30.tgz","fileCount":169,"unpackedSize":1300624,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgPL2vCRA9TVsSAnZWagAAO0IP/2g6ZuA2GlYTfXD7uqOl\nFjTGJn1awi4yV8K4PgkNl2ntwc11+T2v0kIum6AHuWQke7YhoXnUnxpZfpPo\niv/Jn7MRpjktCImQ3878gKC4FziQmKhv7qB2x/m2mY4xZ4zd9DOgrkq/y5tD\nFey9tllT7VZT2wrV8KS1tTjvF0SvBEb3CVDhpl1KmFO1R7W9lj5oE+CprWVv\n+OO/F3KUc+NZMCX+eTEVWkJ8XZBPFQVmbKIoaRY9mthTNmbnu5vOhZ06nso0\n0g10dLcEYwOGz8PyfQ867xlDRuH3ik+dHi12xJPDNohmbCLG4q/sn+B31pt5\nxencpyAGVz3TOnEOXiL2mLwiPMiPJ0TlPvGTe+6qc9vBhLAVgOEM9KMiEM8H\nDDzt0jcqU9U3e0Dpl7Cjvdn0fdgSivkDKy9labQmlZAemJikRqI9Lk4R1Q1Z\nK5WS1mH/1kAsNQ0kgSoFzn2w5H0E2bBW3MAJvBdbbkPNK6FVmpDcJAU5YUfi\nctuu2G8/3gmHa8+8BLL6Rja1ZYyPi/sMPEVK02t2gMN71pd13g1ghfKKNvac\nctdMfuQAOKFPoy4Sv8afYIzRQ7hX9WoRWj5NgTJlmVxQLgU0Zm07kYMmbcYy\nswNytcaT0Sz9KfwduzYnC+upTGxnNrmxEMsulf5dNjHHtTKsS861BZnCnw92\nU1tJ\r\n=YDGx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCaujmH0+NiXhD1OsEcv0n/Sj54guaxoX1kvymnJ6Vx5gIgDSrunz2hycpKEaZN3c6noqwrQxDWiQYp9plOzfuuNJo="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.30_1614593454929_0.2880387911313522"},"_hasShrinkwrap":false},"8.1.10-alpha3":{"name":"micro-kit-atlas","version":"8.1.10-alpha3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"5.0.29","@types/express":"^4.17.11","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^12.20.4","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.2.4","aws-sdk":"^2.853.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^0.31.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.17.1","hot-shots":"^8.3.0","http-aws-es":"1.1.3","ioredis":"^3.2.2","lodash":"^4.17.21","micro-kit-aws-queue":"~3.1.5","mysql2":"^2.2.5","opentracing-javascript":"^0.1.0","sequelize":"^4.44.4","serialize-error":"^2.1.0","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"1181919e75973df3e5a7c438b2e7ca4a2fe1f177","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    \n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n    \n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initService()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n    \n#### TODO? \nDescribe init(options) and finalize(app)?\n    \n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Support.\n  - Ajv validation (only for HTTP request parameters).\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n    \nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `host`\n_string_ _optional_\n\n**To be removed.**\n\n#### `serviceName`\n _string_ _optional_\n \n **To be removed.**\n\n#### `service_root_uri`\n_string_ _optional_\n\nThe URI segment that identifies the service, after the versioning and before route part.\n\n`/v1/service_root_uri/route`\n\nIf this parameter is not provided the routes will have empty segment.\n\n`/v1//route`\n\n#### `namespace`\n_string_ _optional_\n\n **To be removed.**\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted. \n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n    \nRouting\n------\nFor apps using Atlas, routing must be initialized between the `atlas.init(options)` and `atlas.finalize(app)`\n \n#### Basic use\nroutes.ts\n```typescript\n    import { router, Router } from 'micro-kit-atlas'\n    \n    export function init () {\n      router.exposed.GET('status', 1, async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n```\napp.ts\n```typescript    \n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    import * as routes from './routes'\n    \n    const options: Lib.Config = {\n      name: 'check_status',\n      service_root_uri: 'check_status',\n    }\n    \n    export async function initApp (): Promise<any> {\n      try {\n        const app = await init(options)\n        routes.init()\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initApp()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n    \nTo see the example in browser open `http://localhost:8080/v1/check_status/status`\n\n\nThe Router in Atlas has three interfaces, _ExposedRouter_, _ProtectedRouter_ and _InternalRouter_, available as `exposed`, `tokenProtected`, and `internal`. Both of them have the same static properties but with different signatures, the exposed router requires a version input while the internal defaults the version to `/internal/`. \n\n#### Exposed\n\n    static GET(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The express `request` is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\n#### Protected\n\n    static GET(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The ProtectedRequest (express `request`, extended with `req.tokenData`) is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\nProtected routes have a middleware check that the request has hit the API with req.tokenData attached. \nThe tokenData must contain the fields `globalid`, `uuid`, `client_id`, `scopes` and `grant_type` to make it past the middleware. A request without tokenData or without these fields will be met with a 401 Unauthorised response.\nAs a result, the controller gets a ProtectedRequest instead of a Request, so you can work with req.tokenData without worry.\n\nExample controller\n```typescript\nrouter.tokenProtected.GET('identities/me/is-dave', 1, exampleProtectedRequest, { schemaConfig: { params: '/IdentityUpdateGetParameters', validator: support.schema.validator }, })\n```\n```typescript\n\nexport async function exampleProtectedRequest (req: Router.ProtectedRequest, res: Router.ResponseHandler): Promise<boolean> {\n  const daves_uuid = '86d7e731-da23-4e2f-951e-81a04665f002'\n  const gid_uuid_in_token = req.tokenData.uuid // Router.ProtectedRequest says req has tokenData and tokenData is of type TokenData\n  return gid_uuid_in_token === daves_uuid\n}\n```\n\n#### Internal\n\n    static GET(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n\nExample:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\nExample with redirect response:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request, h: Router.ResponseHandler): Promise<Router.CustomResponse> => {\n        return h.redirect('https://globalid.net');\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\n\nSupport\n------\n#### Schema Validator for Routing\n\nAtlas offers json schema validation on the router with [Ajv](https://github.com/epoberezkin/ajv). \nHere is example how to implement uuid validation for a url parameter. First lets create the Ajv schema object:\n```typescript\n    // schemas.ts        \n    export const byUUID = {\n      $id: '/byUUID',\n      properties: {\n        uuid: {\n          $ref: '/UUID'\n        }\n      },\n      required: [\n        'uuid'\n      ]\n    }\n```   \nNext in app.ts we import all the defined schemas, in this case just `byUUID` and we load them to the Ajv validator at service startup:\n```typescript\n    import * as schemas from './schemas'\n    \n    // load all schemas\n    export const registerSchemas = async () => {\n      support.schema.addSchemasRecursive(schemas)\n    }\n    \n    ...\n    await registerSchemas()\n    await finalize(app)\n    ...\n````\nAfter that, on the router any route can validate uuid values that are on `req.body`, `req.query` or `req.param`. Here is route that expects uuid as url param:\n```typescript\n    import { router, Router, support } from 'micro-kit-atlas'\n    \n    const uuidSchemaConfig: Router.RequestValidation = {\n      validator: support.schema.validator, // Pass the Ajv validator\n      params: '/byUUID' // The $id of the schema\n    }\n    \n    export function init () {\n      router.exposed.GET('status/:uuid', 1, async (req: Router.Request) => {\n        return {id: req.params.uuid}\n      }, uuidSchemaConfig)\n    }\n    \n    export default {\n      init\n    }\n```\nCalling the route with invalid uuid will return error:\n    \n    http://localhost:8080/v1/check_status/get_uuid/123\n    {\"fields\":{\"missing\":[],\"uuid\":\"should match format \\\"uuid\\\"\"},\"error_id\":\"1adf7eae-c488-47b3-8c91-fb5942c60444\"}\n\nTo run the example:\n\n    cd examples\n    npm install\n    npm run support:schema\n    open http://localhost:8080/v1/check_status/get_uuid/with_bad_uuid\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client \nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n \n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html). \n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@8.1.10-alpha3","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-lR7pEq+IxrLx7jH0IOZq5BO8uZog9yC0TRftnTHHx8HEQVerag6oNdnzJROlkM8mo8QcbwUU4HPEaknzxPghMA==","shasum":"0fbe462f327bcb8d8169ff6b23bf57ae7b181b5e","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.1.10-alpha3.tgz","fileCount":10,"unpackedSize":23343,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgPTxcCRA9TVsSAnZWagAAF9wP/0iswJeN3nboA8aL4Hwz\nD5VAl/B4ukqYwKQYbRoe6jzTN0VyJQV7dEoN6bAdM38voMGWYOLNavEWT+W9\ns2DJckJQA6CRPiNInxtD3Me6trU+4CNwbgwpwu5bbZHkqSjfoYcrt7ZeP4jS\ncbpS9pQ2x+6UzMyNdQZw9+jb3Dp/TMU6LNtEv95oL2CIk0JFqoTJ38AQs1vG\nccAl6/bOINcRA7VF6gkTQR2j33yZ/jR463tPq+EDQTwOwO4l7npdkDySavwV\nRXZkf4iHfwB8ktLsD148DDSezTCwcLBvljUW8Ril5J+3sTVS7S0R+EGjtjTJ\nERuuirAI0e8rXU9mf4YCU2Wi9IWoYCHp6GP4Jo0RsNW2gFbtEVjHHG/I36Nu\n90/Ip2w5i8bj7fBzHXmP3DcZARHyQzsFScj5i8DazF95RWiRSpA8W184Umof\nqXL5M8snFXjd0HQAgnKfNs8UGnfV2RBYjICSzDcni+tLqLxJKe/d8B8efx3M\nRjJKS02+uHACnp0qyRm6wS1lvd+UagcnDd7aCNzNhui0vh2ThtLX9vKL5bDX\n9FTpj9YX8juIPRcn8bVm+nxxPvENPoKrmm48WDDxJlP4WzU7ADdKlW3ri6sF\n5aLC9JilZwNVmfkdWX+rcFwaYlPtqYDUppsGmiUKMN9KFmWjWLkyPHxMyCxv\nrCAr\r\n=kiB2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCQr5T/qWLagu89jBoMBoK2zR3MF1Np+xwrlUnggbKGqgIgUkyKumBUvr+itc5Y0zXbMv6XwzGfa6sTCOPiN1S3zjo="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.1.10-alpha3_1614625882536_0.7241531401588528"},"_hasShrinkwrap":false},"8.1.10-alpha5":{"name":"micro-kit-atlas","version":"8.1.10-alpha5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"5.0.29","@types/express":"^4.17.11","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^12.20.4","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.2.4","aws-sdk":"^2.853.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^0.31.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.17.1","hot-shots":"^8.3.0","http-aws-es":"1.1.3","ioredis":"^3.2.2","lodash":"^4.17.21","micro-kit-aws-queue":"~3.1.5","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^2.1.0","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"ec2a2ecae29dde1e342287e13b286691164b328d","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    \n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n    \n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initService()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n    \n#### TODO? \nDescribe init(options) and finalize(app)?\n    \n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Support.\n  - Ajv validation (only for HTTP request parameters).\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n    \nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `host`\n_string_ _optional_\n\n**To be removed.**\n\n#### `serviceName`\n _string_ _optional_\n \n **To be removed.**\n\n#### `service_root_uri`\n_string_ _optional_\n\nThe URI segment that identifies the service, after the versioning and before route part.\n\n`/v1/service_root_uri/route`\n\nIf this parameter is not provided the routes will have empty segment.\n\n`/v1//route`\n\n#### `namespace`\n_string_ _optional_\n\n **To be removed.**\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted. \n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n    \nRouting\n------\nFor apps using Atlas, routing must be initialized between the `atlas.init(options)` and `atlas.finalize(app)`\n \n#### Basic use\nroutes.ts\n```typescript\n    import { router, Router } from 'micro-kit-atlas'\n    \n    export function init () {\n      router.exposed.GET('status', 1, async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n```\napp.ts\n```typescript    \n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    import * as routes from './routes'\n    \n    const options: Lib.Config = {\n      name: 'check_status',\n      service_root_uri: 'check_status',\n    }\n    \n    export async function initApp (): Promise<any> {\n      try {\n        const app = await init(options)\n        routes.init()\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initApp()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n    \nTo see the example in browser open `http://localhost:8080/v1/check_status/status`\n\n\nThe Router in Atlas has three interfaces, _ExposedRouter_, _ProtectedRouter_ and _InternalRouter_, available as `exposed`, `tokenProtected`, and `internal`. Both of them have the same static properties but with different signatures, the exposed router requires a version input while the internal defaults the version to `/internal/`. \n\n#### Exposed\n\n    static GET(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The express `request` is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\n#### Protected\n\n    static GET(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The ProtectedRequest (express `request`, extended with `req.tokenData`) is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\nProtected routes have a middleware check that the request has hit the API with req.tokenData attached. \nThe tokenData must contain the fields `globalid`, `uuid`, `client_id`, `scopes` and `grant_type` to make it past the middleware. A request without tokenData or without these fields will be met with a 401 Unauthorised response.\nAs a result, the controller gets a ProtectedRequest instead of a Request, so you can work with req.tokenData without worry.\n\nExample controller\n```typescript\nrouter.tokenProtected.GET('identities/me/is-dave', 1, exampleProtectedRequest, { schemaConfig: { params: '/IdentityUpdateGetParameters', validator: support.schema.validator }, })\n```\n```typescript\n\nexport async function exampleProtectedRequest (req: Router.ProtectedRequest, res: Router.ResponseHandler): Promise<boolean> {\n  const daves_uuid = '86d7e731-da23-4e2f-951e-81a04665f002'\n  const gid_uuid_in_token = req.tokenData.uuid // Router.ProtectedRequest says req has tokenData and tokenData is of type TokenData\n  return gid_uuid_in_token === daves_uuid\n}\n```\n\n#### Internal\n\n    static GET(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n\nExample:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\nExample with redirect response:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request, h: Router.ResponseHandler): Promise<Router.CustomResponse> => {\n        return h.redirect('https://globalid.net');\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\n\nSupport\n------\n#### Schema Validator for Routing\n\nAtlas offers json schema validation on the router with [Ajv](https://github.com/epoberezkin/ajv). \nHere is example how to implement uuid validation for a url parameter. First lets create the Ajv schema object:\n```typescript\n    // schemas.ts        \n    export const byUUID = {\n      $id: '/byUUID',\n      properties: {\n        uuid: {\n          $ref: '/UUID'\n        }\n      },\n      required: [\n        'uuid'\n      ]\n    }\n```   \nNext in app.ts we import all the defined schemas, in this case just `byUUID` and we load them to the Ajv validator at service startup:\n```typescript\n    import * as schemas from './schemas'\n    \n    // load all schemas\n    export const registerSchemas = async () => {\n      support.schema.addSchemasRecursive(schemas)\n    }\n    \n    ...\n    await registerSchemas()\n    await finalize(app)\n    ...\n````\nAfter that, on the router any route can validate uuid values that are on `req.body`, `req.query` or `req.param`. Here is route that expects uuid as url param:\n```typescript\n    import { router, Router, support } from 'micro-kit-atlas'\n    \n    const uuidSchemaConfig: Router.RequestValidation = {\n      validator: support.schema.validator, // Pass the Ajv validator\n      params: '/byUUID' // The $id of the schema\n    }\n    \n    export function init () {\n      router.exposed.GET('status/:uuid', 1, async (req: Router.Request) => {\n        return {id: req.params.uuid}\n      }, uuidSchemaConfig)\n    }\n    \n    export default {\n      init\n    }\n```\nCalling the route with invalid uuid will return error:\n    \n    http://localhost:8080/v1/check_status/get_uuid/123\n    {\"fields\":{\"missing\":[],\"uuid\":\"should match format \\\"uuid\\\"\"},\"error_id\":\"1adf7eae-c488-47b3-8c91-fb5942c60444\"}\n\nTo run the example:\n\n    cd examples\n    npm install\n    npm run support:schema\n    open http://localhost:8080/v1/check_status/get_uuid/with_bad_uuid\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client \nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n \n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html). \n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@8.1.10-alpha5","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-4mbWTzh/FElhmStuFOpI9njdmIMpJVhRdzUWLsa80Yer/M8OgemPpL8HKTU5pMMRjIHsU2gBOSmbAZYQwQyUYA==","shasum":"aaa47d188d7f3fcd9f803d8f95ee189d8d92f13a","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.1.10-alpha5.tgz","fileCount":61,"unpackedSize":144002,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgPUQZCRA9TVsSAnZWagAAzGgP/A2ZK7pmsAsOhGL5d+Xm\nXHlcuztCjyFyIzySuglpW/NGZ41t6Ibk4uCr7SparBj/uqobzFexSQtsgtK7\nG4BxKgqaV4yAXcpg6YGiK/4Z8XbNbA7pcWpSebBW6Huw9eb89bQs7LAkOAsm\nZrPdYDgvdzXMokVrjeQyDJqMlghHKYkOY1flb5/vXDq0jQDCpEoa1usM2whx\n8cbSs+hNHbcSBoiRNeP6IBJvNELF3nRkQvY4a6VoxkiQaoYczCdg2BHerBop\nlOi1qs9ITr3eDZWVA0O+GP3LcyK7/MY0+Kl3x5BU+55b8Qq+3Q7eRcAXUt3m\nTuyWvuVgQEQQT+D5GPn0z3DhoAYtJO3uR15m/p1rYCXlQyBNjMqhe8uvUEJ8\nXshfcgCusd55tZFx12WhQPn7DGb4eN43xsPHlFATs/Yfe9pFSAQZwyP8v7qf\nw0BfJGgr8pjAK+ee4aXLvs0f36PaBuvQC9GFM59eTOXEjOxEdjFjmQKj7mie\nw4QCxwbJUG3kTcC9kZvHixMycC+SzMlVa19EB8uxWbC3RGg3629P/hBqZlK/\nihiaeauV60qzJ+ZMP1J+upB4h72YqCH/EtVKZFEp74svGY11E+nGuRlflg4x\n4BPQigoLc+1kbTDC8cYe654KHEPVsPNaYzgPGNrBY+JpcPfE14b3d6RPNyFq\nhc2/\r\n=kytV\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCjs2HLRtTho/VJstHfzrm8BrnPTBjRThheAt6FOdyRkwIhALHYZwK5kng9+RvJJwsUly6m7Td+LWP7m54LbKEOniXK"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.1.10-alpha5_1614627865139_0.8686356465177547"},"_hasShrinkwrap":false},"8.1.10":{"name":"micro-kit-atlas","version":"8.1.10","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"5.0.29","@types/express":"^4.17.11","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^12.20.4","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.2.4","aws-sdk":"^2.853.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^0.31.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.17.1","hot-shots":"^8.3.0","http-aws-es":"1.1.3","ioredis":"^3.2.2","lodash":"^4.17.21","micro-kit-aws-queue":"~3.1.5","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^2.1.0","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"ec2a2ecae29dde1e342287e13b286691164b328d","_id":"micro-kit-atlas@8.1.10","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-MMbxZl4SxfdHxPHMAmhCa7NbhLP7l8jPie+MjCwgPHevTyaTZAqarthrjAw7Ypoi/2ZQnu0BPGk4tkbZ21o5rg==","shasum":"2e0b71c886d68272822fef49d8ebfca0f1afa388","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.1.10.tgz","fileCount":61,"unpackedSize":143995,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgPUvWCRA9TVsSAnZWagAAuAAP/3aXST58ylphDtCdVdoA\nYgl2DaD4QxX4teMRlLoQWMiA8SJoyRDJf4hTaHogs7vdgoylOcT+4NRdbXt0\nAhjexXfpVmuZchgpM05fmnOlaTmlk5ZWhUCCT+iA8lujDHhu0rzl9zivHDAi\nw2d+SopXAodCLSRB3Xbba750bVaytKK1bptB5MUwCvAxK/eBTNYREddu1t81\n3TApoCzdGgFheweSKdDl8zTR+LWhqFfDJjeWmbSTQpWEUK/COBtfe6XH7LSG\n1a3Ze0+/ft2wpo1fR6mfSOLiF3RQbKsn2r+NPVNIZv/RNkjQcznV58QBG7LL\ndEyS+TVeNIR+CkcEPDr8qnfKZoZaUlpAIj9McVbY4ZmWFIjYBxI7SpCnVBH4\nsdX9P0ZO/bk6azlS4h7cU0QvDsV7tn8caW0BNqEGSNkysvj94ugTl+kGKwwY\nEQ+pwWTaTFiQmeEcPiWfDGFmgYdwSdppAaDDqqzUS8q1LH5cv3u/KoAQYZdN\nq7ATmjsv6lo5tWHIRctkbsp9Ty7+cfmu/Tw9yBBxIyuXLQJVOTOiJwl8KJO3\nnx4GYL4P05cRbtzsdkFFnmduyO9wYcVfQsJMENkqTcVEaSfFtIh/lU/1/6NF\nAel3vDMU51TbXID8tbzKB1qlh/qG6A9ABb1rKpJtYjGziWGqu47d7QN8stwr\nR9ya\r\n=itOp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDGYjR8oXRgDSsBsevQThNJadZBoJns+l/7Uw2QwUysLQIhAJDx+epm4n+w+T+SFOMseLeD0xsuT1bCB627HxcMWdVM"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.1.10_1614629845457_0.7834472668674963"},"_hasShrinkwrap":false},"9.9.31":{"name":"micro-kit-atlas","version":"9.9.31","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"^0.30.6","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","opentracing-javascript":"^0.1.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"a3d3e14214c6f2a3658a9e5b5cfbc58e4204240d","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.9.31","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-RnwOwQ6GgPcgEXSq+uU3h+D6avdvHkujGdi50nBNFUdxy0ul5Tqe+PsrQkAj1AiY1SY2cThuokspkzZbEFQ3GA==","shasum":"14a39358a6e1a956d92c1474e6e07ca4a251866c","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.9.31.tgz","fileCount":172,"unpackedSize":1302152,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgRpdLCRA9TVsSAnZWagAAHGsP/R9TKdbK4varW4oxOB3d\nBoS25MYSOo+5qJoFOGRbU+AFfLKI2WcByf8V7kCPRwmZ4kXPtV8bNiewZ5B2\njYBjeORykdDDsfY+DDSbR8Lo/kybKP4Mo4cyo3JfajdS+mgUdJ/M7px+nusG\nZLxKeguV19Wzeb7rucyHel0StfsH42M3MzRkJse5423sXhzzxBsu3kSwA0ba\n8dgY8qe8VQ7xS/GvxwVmeAgjMQ4NWU0kA3UZWmNC0gCG4G8b1jNI6sTgvJTV\nzv+LbdLEgDsrVdW/DinIBTi9v7b1G+LcI/W7NGIzzCZ0joqvXeY++fTCiU1q\nMNdVmSUc7DHRepoMJJmIls/61p+pINbPap1Zl5uGkMUAnX9h4m+g177VfNUL\nXlXmfhivN82xj5TpLplkKcxQN49Ge+YqFBhI6JFjvXygXcSc4lfts6S0NiIE\n0y/J372CFMPnmXK2nkPNJof9NTwmbe+NQNG65eTbC8rJ2AN6XkRMCMs9lthf\nWMFzxcbmNqxQ2ek7a8dlKzOSsTP3g1Ag0IiBtk7J1+NIrNbn4BqCAs+JLC0Y\nNNo13NsIemn3eQVRTiVVKw5ldQALPf89zAxg4sxm1PRI+syLSRlMxPAQijHe\nP0TsJ/Mt0aZzAnAKoL9eDfmlkf1dYmokciMAn/XI8M9HIDsxc9D0rTWfwRUN\nQ1mj\r\n=yIK5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIH/Vkux46KFqa2L3yQRfBJwR2uBfximz6jZWbjxGhwtkAiEAr4RSbiNOjz8WlQc7V0mO02lthn6bC1/qj3Tafo1a7BI="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.9.31_1615238986345_0.29119358923342253"},"_hasShrinkwrap":false},"9.10.0-alpha.5":{"name":"micro-kit-atlas","version":"9.10.0-alpha.5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"^0.31.1","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"d8db43bcb6a44744cc49f1c15ce90b8cc60dea97","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](#routing-configuration).\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _required_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n\n\n# Upgrade from v9.9 to v9.10\n- add `@types/express-jwt` package as `devDependency` (`npm i @types/express-jwt -D`)\n- initService call: add `routing.jwtOptions` configuration.\n    ```ts\n    jwtOptions: {\n      issuer: 'https://issuer.com', // issuer (array of issuers) of the JWT tokens\n      secret: 'secret key / public key', // secret key or public key used to sign the JWT token\n    },\n    ```\n- for integration tests use\n    ```ts\n    import { mockJWTIssuer, mockJWTSecret  } from 'micro-kit-atlas/testing'\n\n    const config: Lib.Config = {\n      ...serviceConfig,\n      service_health_config: false,\n      routing: {\n        ...serviceConfig.routing,\n        jwtOptions: {\n          issuer: mockJWTIssuer,\n          secret: mockJWTSecret,\n        }\n      }\n    }\n    ```\n- remove  `Lib.Config.dynamo` and `Lib.Config.elastic` config\n- `mockTokenData` is now a function so yu should replace any `mockTokenData` with `mockTokenData()`.\nIt returns an object with getters so you cannot use `{...mockTokenData, uuid: v4()}` any more. You should instead use `mockTokenData({uuid: v4()})`.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.10.0-alpha.5","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-Hh/iUfcIyrVg6pVp0UT9Id6N1TFSbtchAJUda4vPJrw3jR5gGBIQWQ0fnpp1q1pjCtfmTqN9RZVUvOTQFPltTA==","shasum":"b01fd1c75af346a1d5b4d3d6074804a4536bcd17","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.0-alpha.5.tgz","fileCount":178,"unpackedSize":1320285,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgSiNJCRA9TVsSAnZWagAAkC0QAJRd7lsbi+sv3g42FLZR\nKWbQiQxnI0q95U3guR9xEK1xj9SpgZScAByJegQ+/H+8DR81DbShAysIkKIv\ncKpKJzSzYYTE/P5vw/umjkffRn9QIoCRj4kb8H7ytyJo1q3ZjSAwi91Tj0S3\n/eCDTS/uFpl/dgnffCXDyhmLc1MAzCWyGH0FYoXdB8oyacBkKfHfbeVPKw2E\nd5ndU7P//LxA43134F4c2NjVyaJL9WLrgE27wGIOvgLU2xXMFN2eoLcMy9Te\nYl4mQAlTbIzDP6aWOMcyevburQL1gK74ft9GIpw3YMRjd0IQuQQSjObqnb8e\noJa+KzdgdWwYny/jOp+QRfm6kGzInUhtj4S04Gd2XXSzpYWgMfRr91RS8ZCZ\nLXNz3ao61QS6/yAa5zPLgw8gFj/yQ+uUZzz6jSKJxqal24MOYFixmHctAqy0\nNq9VnZ5DnlJclTVPCOBH0c10r2CnTvQlfCwz4n6/CPL5AbwtGjht5GPlCOM0\nI3ZYdT2D7asmC47lWfAdtZsiAov9aD4JeY27xLhXUGxJvSaR/4qn6sKTFI2c\nGnwwxJD8aalrq8U0H6zEqryF7dNTiGwFfxIrNUE6rtpKA4kUmaqXZd0OwlVV\nXI9CA7FXuCS0OVNCDIpmJj4nN/zV0a8IQEzfTaAjsFq2YS5D067MfSIiLVTV\nC1yO\r\n=Wymf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE2ZhKdeddJvEFtFtFhV3mOoYIBppHJw85bVc3NomhNKAiEAuGoYJe/qDtLCHtSLmlVq/8Kw0kGqCfZG8vbrGZJ6RCU="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.0-alpha.5_1615471432575_0.0742837817914419"},"_hasShrinkwrap":false},"9.10.0-alpha.6":{"name":"micro-kit-atlas","version":"9.10.0-alpha.6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.unit.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.8","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.14.1","@typescript-eslint/parser":"^4.14.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.18.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"6ce866ab8d491eb65bb7f8dfd9bbdda80910f983","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](#routing-configuration).\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\nRoutingConfig object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _required_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n\n\n# Upgrade from v9.9 to v9.10\n- add `@types/express-jwt` package as `devDependency` (`npm i @types/express-jwt -D`)\n- initService call: add `routing.jwtOptions` configuration.\n    ```ts\n    jwtOptions: {\n      issuer: 'https://issuer.com', // issuer (array of issuers) of the JWT tokens\n      secret: 'secret key / public key', // secret key or public key used to sign the JWT token\n    },\n    ```\n- for integration tests use\n    ```ts\n    import { mockJWTIssuer, mockJWTSecret  } from 'micro-kit-atlas/testing'\n\n    const config: Lib.Config = {\n      ...serviceConfig,\n      service_health_config: false,\n      routing: {\n        ...serviceConfig.routing,\n        jwtOptions: {\n          issuer: mockJWTIssuer,\n          secret: mockJWTSecret,\n        }\n      }\n    }\n    ```\n- remove  `Lib.Config.dynamo` and `Lib.Config.elastic` config\n- `mockTokenData` is now a function so yu should replace any `mockTokenData` with `mockTokenData()`.\nIt returns an object with getters so you cannot use `{...mockTokenData, uuid: v4()}` any more. You should instead use `mockTokenData({uuid: v4()})`.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.10.0-alpha.6","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-pD8HN4h4i04pA/X83TaC8xqRVyitnnyuUQhsWnRh1MPRcTBt7324ClfL1IcDF/naH6InYK5K/6KMpSiXv5zq5g==","shasum":"1269f8f55886fc39fa6836bab6e866e86f4d9ed9","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.0-alpha.6.tgz","fileCount":178,"unpackedSize":1320285,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgSjRQCRA9TVsSAnZWagAADOkP/jnr7rcE4Tg2Gtcjo9V6\ngz5Y3UkEE1e8aICpWC62HG5o4PavKYuHDg1V1pxCYAaUkK+8O71q9SwjrhmP\nMuDIWg70TvPe/toD6LMOpddmPiX2XSYIgeNfrIk05AUyu3mpdyZcqfP96VTT\naFqjMnTkQTQZmYpPGsMfXKCitVWRG4dkwW6M/lVmhqOSfewAqoWzQZtcwmho\n0mhyF1aKa0okXPh0cvQ02RLJFKYd3C6WuFtZSun5SFSj9adzmHlR0+1upxT7\nMAd9zVWWmPXocJAyHu296c1aYyBuBGCYnThSxswLX7UPS58HHHK0w4FWR+Ry\nTQeOZp4UfjPHc97cQONNOQnM62qACEcyZxPvZbRv0NUET6M0RuatKLP2fL04\nR0H3qrDSDIYQCZ6MH0bNBqoIAInwbJagE8FnNT61UpKIi3IHq0KVHTqaqZas\npoOdcGN3c5xaLykFVKKwmtANZrXXm6lrmZ2tBBJLTXqQg0sOGpk0UOpV/fqx\nOoVSRi4GnrHAN9bXDIvoN9biG+pOGp/ccZNGSiV3+lUyBECxDkb8iLbsQwUP\npvEIVFoyO1t/QUQ00eghsSMC64ItJ9hgpAsSAVzom3u0huIy0Vdbrrvebwer\nggtk3jB4uxl80+nQW/szOQLw7ue18yKywWGG33BxUU3UhcxvEfeMNvmgsdAU\nBPea\r\n=NmlO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIH4KDid+HcXV94PGrUs47L5QmVLXBjiiiLPieyS1vw4MAiBFXv2azH+ED+duxjYA4Jlt1Va+q2ZoSDe3SqGC7QMVcw=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.0-alpha.6_1615475792105_0.7519577276263485"},"_hasShrinkwrap":false},"9.10.1-alpha.1":{"name":"micro-kit-atlas","version":"9.10.1-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"b53e89a22712fff7176f3131b58c223264c3a65c","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _required_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n\n\n# Upgrade from v9.9 to v9.10\n- add `@types/express-jwt` package as `devDependency` (`npm i @types/express-jwt -D`)\n- initService call: add `routing.jwtOptions` configuration.\n    ```ts\n    jwtOptions: {\n      issuer: 'https://issuer.com', // issuer (array of issuers) of the JWT tokens\n      secret: 'secret key / public key', // secret key or public key used to sign the JWT token\n    },\n    ```\n- for integration tests use\n    ```ts\n    import { mockJWTIssuer, mockJWTSecret  } from 'micro-kit-atlas/testing'\n\n    const config: Lib.Config = {\n      ...serviceConfig,\n      service_health_config: false,\n      routing: {\n        ...serviceConfig.routing,\n        jwtOptions: {\n          issuer: mockJWTIssuer,\n          secret: mockJWTSecret,\n        }\n      }\n    }\n    ```\n- remove  `Lib.Config.dynamo` and `Lib.Config.elastic` config\n- `mockTokenData` is now a function so yu should replace any `mockTokenData` with `mockTokenData()`.\nIt returns an object with getters so you cannot use `{...mockTokenData, uuid: v4()}` any more. You should instead use `mockTokenData({uuid: v4()})`.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.10.1-alpha.1","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-lqpJVfC9uTT850f2CpW29eOeLgnc8R7rrkGPH40131P/lti2I5QsBNEJzKPLfw4kvODhQrTHuqVD9q7/5Usmfw==","shasum":"4902b212ea3093a7aedde5e50a90e2beacb07266","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.1-alpha.1.tgz","fileCount":182,"unpackedSize":1325312,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgUHB6CRA9TVsSAnZWagAA9C0QAIcoKmLagSDiX5Dm9U3R\nRANSbrYOphffaKnQQEAn7q3m76jxMWvji0CPwCamam36Dtuu5hbWVBDdgLL2\nODcWDIpPIRCcROhfv8VJNUcPBOCrbJeKNyj9ZBguorlaKvOX0TdfTCfH+M+g\nMiaUjdv4y/c/p0Z4wbNm3ZjrueK6lz5EJqBEVsGvs5CksXKqajx3KhwI6E7N\nAooztnP57YPLMoZRVS90XVOT8rd47equhcBNfgPGoRYhyTQvvUptjCCXB9/W\nuIo15n7yJSGnNBKGl98eV2CvqPGO5Qo8hM3f6XDUwpDtnRvyvEYcffJ4l9H7\nWmG+xnuG/FQoCy/q8Fwo+7Wyrbppt56mJHRtWmawcRmpUDeBzEqs37W5ouNJ\n53V2QEotp9c9d0nCEwsHiCSKyp/AAfOa3dbq/h/UIpKe5ZoFinCJFuVc5zJW\nFDtyDkugOca42YohG/4gBJHXiHipn3UrmH30JsDWMVXRpwLQFGkE3aAI1OvZ\nZGRzfN72Z4gT6r7HBERj5LVXEP89vy6LSS3El2SKJKscZFIeQKERcm0f7gyP\nJxfiqDaP75r4PfWi/+yB/pymXQe54J1AmurpDvUwvFBFmbiupttTEk7GPiKN\nSYL+eIvnkZgnsHVqKAhJ+D8Z/Y8Zv9doPV8r9LMpor5eRbZQK31OfTLs1sw8\ns6ty\r\n=tquq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD2Q7mVZn4kclVs24Bqxil+jvjY1wi8jmv+cfYbY+2ziQIhANKxKnc0TL/ihlIu2iMfuxpT/etfUCUo8jnigH1go5iD"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.1-alpha.1_1615884409714_0.38720757643200754"},"_hasShrinkwrap":false},"9.10.0":{"name":"micro-kit-atlas","version":"9.10.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"6608b4d28451c206a7dcea4342b76e9cfa8cde19","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.10.0","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-1Ys6Ysne4y4YzEupV8FAC2N10VGn5PZeiQ0VLmEXDCSR237/82h2McqVdsXDsiLArkdisUcepisjdHkCp8QMxw==","shasum":"1d7331758c745b3432b25b9c12e563ffbe1a00d5","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.0.tgz","fileCount":182,"unpackedSize":1326154,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgUIMRCRA9TVsSAnZWagAAjrgP/2v8kYNNdkB1PGMTS9+F\nPeQsK6y98s93oTXCRU7RVZNJaj+GnJhu1qMvfyX6Y6eJc8iaqOjfipc4GqX6\nJqpl1VGpoFXKBIwJkmTdO1hkNM3SP5sueqTeJF0Yq6ou+4tsGIpj1ZkVpiP7\ngQPZm0UAIXS/rsZfqlAlYSvVEVFzM/VhM65jCA7dh/oiSMXXp1p0WLZYC6Ho\n1KJlFfjbO9t+0zGYduLtm0jtE5cFa7fd2XDQtFAhybFh+tJoO22guGY1jyBm\nai6CbdIcLgGi3fIciBY2IVCkQHC5UFyrl0nlgpiNusK9+dhx4pvv4vHjZoKF\nsVLMwMwUZrwdqpXBoZoPUKLJh9qx+UhMjUsXcgHyAkmCJV7VCwgZioJtkQzr\n6auidiV9zGKB3X9pa1uU5uXHfOuyvcV62144PaOuXHjimplzI7TWIE3EuSFG\nBcCIQB7bhcRp+06z104qpqqC9zsI21ns13e0Q0WfsKrHdyykpjL5RikXKbdG\noIOrgdOTljYYlTJpXb52JB9mZJLOgOcLlOfRnMh0NGfAade2oNdkINsmZMXZ\nzQOdLJ7iL4sJOkIsHsJqIDpgAJWMypp4GzC7ulzLnNNWzxaoPXc01OtGOvV/\nqA3AZp8jlH353MKQ208tMqyOmfsMbY4IjCyk4DyOnzDqPW7fvAwOikQ0V55h\nYMz9\r\n=UUB0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCO5wYBOGnlMCLyKWY668xFn39ghctF724trAI6G+TLtQIgcEAMPGPRwRb1S14LX6Tfimi5kj/gnlVsj/hKRJ1Gd84="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.0_1615889168733_0.4822932640319024"},"_hasShrinkwrap":false},"9.10.1-alpha.2":{"name":"micro-kit-atlas","version":"9.10.1-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"0e26117d91528b3002cf69930c1fb358bf61e2e4","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _required_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n\n\n# Upgrade from v9.9 to v9.10\n- add `@types/express-jwt` package as `devDependency` (`npm i @types/express-jwt -D`)\n- initService call: add `routing.jwtOptions` configuration.\n    ```ts\n    jwtOptions: {\n      issuer: 'https://issuer.com', // issuer (array of issuers) of the JWT tokens\n      secret: 'secret key / public key', // secret key or public key used to sign the JWT token\n    },\n    ```\n- for integration tests use\n    ```ts\n    import { mockJWTIssuer, mockJWTSecret  } from 'micro-kit-atlas/testing'\n\n    const config: Lib.Config = {\n      ...serviceConfig,\n      service_health_config: false,\n      routing: {\n        ...serviceConfig.routing,\n        jwtOptions: {\n          issuer: mockJWTIssuer,\n          secret: mockJWTSecret,\n        }\n      }\n    }\n    ```\n- remove  `Lib.Config.dynamo` and `Lib.Config.elastic` config\n- `mockTokenData` is now a function so yu should replace any `mockTokenData` with `mockTokenData()`.\nIt returns an object with getters so you cannot use `{...mockTokenData, uuid: v4()}` any more. You should instead use `mockTokenData({uuid: v4()})`.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.10.1-alpha.2","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-FZRtTI83Q1cQ3ymGtz1JWmYQqzECl+USmvqA3doknP/acpy6MlS+MxcRV7KBr2GeNgDs7SAhEZ7jQgjbOGIQJA==","shasum":"31c8fc0ade5fc7d19a14492003aa0e7b1b783a1f","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.1-alpha.2.tgz","fileCount":182,"unpackedSize":1325279,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgUIMpCRA9TVsSAnZWagAAwygQAJWDHI2dDoK8lL5Ii8k0\n56VvLju7w7q8jRPisD5BcoRPRiBKOwgL6PRWTpDc9Epw6KyS0BIak+PUJio/\ndGVIIYubtmH3jRJbVBemuDoouLbg/sYK1s/cre9oTn57X7aILwtSoPAa3OY8\n4hPklDOvsMwIsbLd7VzUkikVjz9apFOdwh6Ro05XHcOigejV15jEeZZmQb7T\nRsqfUNpnN/kKYdr+JXNReBZxCEd3Qz2iev99RezrOGkOFtikecbfPzZBeWah\neoAxI1DaUfnKAG8Sype0UPQrhHJ/m0UtSPilLUuu/+GFtpWec4SrvYFxRX6s\n1ZUO7OOD1vOcThGTwsoXgTfGBngEX5+9HbVQBnILYBW39w4h9MNgY3k+qILZ\nApxXFQD+ntwwocpffxfKLQYalYeNKGoGy/V0E6GoCeRfpBiOfj8DEVFWwVYq\nwCmL7vyMn1ULrN0DFcp1P5CTAhOy1JmFFAd8wIG0ZdHHdkuDAVD133LOCqph\n+BfNtWe/0jQGm95umXXtE4nUKYNVMxFxCtYObOpEi5amtt44KOZScOP+kLGa\nEl2o/vuq1txMuyKmD9q9slFGncwOMNYrkhq7aAfwuAEnbZ+NsYi2OpZRFCs4\nfKQT3i+EgLYCftymb+qeTkttYOiLvaco8AAzU6mSLeYLCUxf0a7NUX06elVs\n64PQ\r\n=dNKN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEuqAlaZH3GSuBdvqQFrBX5RGsL4F+3wjvLbzWlXb7XLAiEAvVnZ13BAKRTEE7C6KgbXiINPWFy+hzGumVkC9vpk+pc="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.1-alpha.2_1615889192411_0.9722681476083752"},"_hasShrinkwrap":false},"9.10.1-alpha.3":{"name":"micro-kit-atlas","version":"9.10.1-alpha.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.20","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"5f23d65e700a2cbcf043b42e6fe32cb1dc401928","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _required_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n\n\n# Upgrade from v9.9 to v9.10\n- add `@types/express-jwt` package as `devDependency` (`npm i @types/express-jwt -D`)\n- initService call: add `routing.jwtOptions` configuration.\n    ```ts\n    jwtOptions: {\n      issuer: 'https://issuer.com', // issuer (array of issuers) of the JWT tokens\n      secret: 'secret key / public key', // secret key or public key used to sign the JWT token\n    },\n    ```\n- for integration tests use\n    ```ts\n    import { mockJWTIssuer, mockJWTSecret  } from 'micro-kit-atlas/testing'\n\n    const config: Lib.Config = {\n      ...serviceConfig,\n      service_health_config: false,\n      routing: {\n        ...serviceConfig.routing,\n        jwtOptions: {\n          issuer: mockJWTIssuer,\n          secret: mockJWTSecret,\n        }\n      }\n    }\n    ```\n- remove  `Lib.Config.dynamo` and `Lib.Config.elastic` config\n- `mockTokenData` is now a function so yu should replace any `mockTokenData` with `mockTokenData()`.\nIt returns an object with getters so you cannot use `{...mockTokenData, uuid: v4()}` any more. You should instead use `mockTokenData({uuid: v4()})`.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.10.1-alpha.3","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-AxpRuT54HHEB4PqfFLN8zlq5WG5LQoq6gTQRy5GmV8XnPhrdfSKkJ1Ii/aRBtMqBg1T6ilGQs9AI2EGjjblwvA==","shasum":"38b062f7b96c0aaddb58aa50b91efeca956ff4fa","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.1-alpha.3.tgz","fileCount":182,"unpackedSize":1324960,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgUKgkCRA9TVsSAnZWagAA9lQQAJn2c0vf6+1S0GS47Sq+\nfkfMnQ/AmV9C521D47FiyyagoJMeNnXHGxbgSr3KSLKycXg/h2A1rKhCIJLt\ntoBSr2G3XjNo6O+8dKh8KIYXm8ma0nNybJLJYXeUWX73YdjjOHa44tK+Gtd2\nStvdVtqa8g1L1RFYl1x5NYP5KbGI3k+ekvSlsaOV7gBe3ItTTlC1rLIML7JK\ny5YkfPiXS+fUFdcJ0XJVPyu3B6rfprCydCU/awqsG3ux13q6JUv+O1dDHA3G\nbJ9SRFRgMOigjzQ7JI4QTHty7rOirKU6NVCiMIvT86Gie5eojX+HOXpDUij1\nxmb6xDyV5fTEY1rtQX5U7Q4XBiP/rQF0Wb6ZcaJhUV/uZMUZp5y3Ye2NRNei\nTsrWGqEcHSxkLF7TH/XiXNfzcv1OuFRmGFeriuImJmx73/p7lcP+LD6Psngq\niRl2K6UZzceVfscGpN1hzxKpMX39E8Im7qPGFdwHXTbDYtKyPb07/29u1tf7\n8k6RmGM6vsK9yQZ2LsS9ZbIaRvODVBR4MOIWT7dtAqPbIzp0vQ9bE7NGGh2X\no3+CiFzn4T1ugoJRJSTADNnWEhr4oUzpie4LJty2LSFJStMnZsclAwDfqKLh\n8992fanuN+p79HwBKx8y6tFRBAcoAijFbkAmp43LxEaybPTW5Njf/26lGqUT\npxTd\r\n=5td3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCHsGg5DJh4joMHmTs7iZU5ZK74sMzvEJcPEY+vn7TikgIhALTXNQVtxoozUxrpSoFVHlpIgHEme70hZa6AyDKEcjbn"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.1-alpha.3_1615898659652_0.811001170109831"},"_hasShrinkwrap":false},"9.10.1-alpha.4":{"name":"micro-kit-atlas","version":"9.10.1-alpha.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"500e8e58c63069a352d714bd26d1b3a64e958bda","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _required_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n\n\n# Upgrade from v9.9 to v9.10\n- add `@types/express-jwt` package as `devDependency` (`npm i @types/express-jwt -D`)\n- initService call: add `routing.jwtOptions` configuration.\n    ```ts\n    jwtOptions: {\n      issuer: 'https://issuer.com', // issuer (array of issuers) of the JWT tokens\n      secret: 'secret key / public key', // secret key or public key used to sign the JWT token\n    },\n    ```\n- for integration tests use\n    ```ts\n    import { mockJWTIssuer, mockJWTSecret  } from 'micro-kit-atlas/testing'\n\n    const config: Lib.Config = {\n      ...serviceConfig,\n      service_health_config: false,\n      routing: {\n        ...serviceConfig.routing,\n        jwtOptions: {\n          issuer: mockJWTIssuer,\n          secret: mockJWTSecret,\n        }\n      }\n    }\n    ```\n- remove  `Lib.Config.dynamo` and `Lib.Config.elastic` config\n- `mockTokenData` is now a function so yu should replace any `mockTokenData` with `mockTokenData()`.\nIt returns an object with getters so you cannot use `{...mockTokenData, uuid: v4()}` any more. You should instead use `mockTokenData({uuid: v4()})`.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.10.1-alpha.4","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-Wbb0b5ov5PnfCaBlvEwPb3PB2AfFxmHyh2PZDucnPQvIfll4aUFaj54fXXRi9EIrTyfzxZuhU6tTuf5RXU6xFg==","shasum":"86d4c1df629617d8902125d12c539eff1e3971ed","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.1-alpha.4.tgz","fileCount":182,"unpackedSize":1324960,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgUfprCRA9TVsSAnZWagAAS7EQAJKlDzRVi2gmdFp5M0cM\n3rONR6RBSfLenjkb9s79OrLIO4RqKiLLr5qoVdYUiiZk4+lF8FjRKH8U4JV5\nB1R5v7Bf5BMAjfU3ThA6VKJicRInMj2JiPpsuYZgR5oQWymN3FlUBKgdNq2R\nGBmUqIPjDaP4hYYiTrDJYXbA5b0/6lcy24qv/F/vvYFBcwHxyna1UIkc/aQ6\nBedbDLxLY6xC7g/IX9Gl9u0XwMQ10y/ainFUIVUb51jRulWrEkNnrhJARU9v\nvP9jiuSpm5EqcjzQ5hLxRKfqnM2uz3nTXoOF78Y8qO7Q80xQmCFzhtECocoM\nOBl1JJu2CDQKf5oBMrP/oXqsPlSgVA04xVzLhL6sgY3kFLmarmowHam3lVos\nPa7pEctEA/1BQKZ7n23FY4lqHEoMXEpkRchRDZL+GoercbugD0fu2PvkoDjO\nmaPjnf0qDHSzJv6ieRthn6cJ6lSdyBQJYrxZN6hgQZBFqVJGjiqSCeovN5oB\n8/dm+IToCxt864cwLdOgk/esgmc2jBW2NhPkwUXwUzzsM3UavyMYTEIOGFFf\nXoUgJDtHA9VV63ITSCHZUlIwNJXJaxZQhAQIkUu1YmGOPk28j4lHNdE4cZMc\nllxFmRjOzN2GCBPDB6o6huoHkFLPf6W5PvEYKk0K7wmLRIklSt3Ccc60oHle\nmtgZ\r\n=8JMP\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBFwsHhXF+BuDHqa5m/8YLfyJ2UYy09rbxzLhGl5RB6PAiEAovJ2VmXaE/hymxP5D2EuSZj7c7RV7El0fhuTPSjXHds="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.1-alpha.4_1615985258579_0.985698470075467"},"_hasShrinkwrap":false},"9.10.1":{"name":"micro-kit-atlas","version":"9.10.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"b225cb373e06838f0af361da8c558f6db2e910eb","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.10.1","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-aexbPTiz+IsikF8RoH7a3nu0TKf1hWAzkb9CPLojiicZjfk1qrJOOY/c3EINkeuClAhpCS1y5hnKkazTcXIzXQ==","shasum":"fda197567809cf5a6b29aa15ed47bd06a61b97af","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.1.tgz","fileCount":182,"unpackedSize":1325511,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgVJELCRA9TVsSAnZWagAAuxkP+gLfnUvR80KcIASTOu9x\n9G3gRPg+DvN+8It2Y5Pxb7P4Q30C3ER6ZtnbBIACJTK9tvHbYhsqjJQTWtqA\n5SzcOiXTRHSgUs12K4gLzY0AiwdIWETL9liaakXuMmplrVTy7PvuLbKZ9Cvu\ngNrzpRgkN7XFlfUVZ/M6VHI7m/6hGdUiYpq452rgEonLJWGoyeLLrMpQoRQw\n7tAAv7oRG5W4gh/zspixMe1azIn5DRQFwJT9Rdyopz2URWoyKSzn5j4tV9PD\nZBOrmu2IUp6MfdM5bgR0NRSlRZKCTtnb2zU6CxNkZdGuQ0FhK0nBluicQJ26\nUIiP6vaLuG1TT7ihAd2CCniYQ1KhGET2iCc40bO38os9qQrHO3HSZ4sHn6Ju\nfF+VnXBHRcDSUKij1e0UCxw/Xe7ksj38717VLDFkSIICXRf9ySv21vj/pyWi\nk7WICVfCc7ALpt+TivI2+7wQThTyNpnN2JUYNEPC0u6fsc+yoBm96LjMtLUR\ntpKZS+nC78w/7t1wNGJ9ZC9yC6ukBSlOow5lYLmavYEVNnsoPwrX5ZH1ke6B\nn9RgIgOKlpDE/bOFapSwr0jUZiTx1wJs833tWT8CXkNaqI2wLqFQrMrLR2dR\nmWWcszrDxQ8z/wXji4RIzqaoLXSuBpgHbHJMhXI1E4fC1kUaxuLerSZQ7OP7\n/cJt\r\n=KQXO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCQI1sajS/oQFWNDGYcphUTAJrs5CkiWcGIu8oPi6FEDQIhANXhtt5EvVVHMcp1hUKVCKpTueGSWbgSim3CSfoGebt+"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.1_1616154890436_0.23231052204395075"},"_hasShrinkwrap":false},"9.10.2-alpha.1":{"name":"micro-kit-atlas","version":"9.10.2-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/core-services/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"64e3a7dcd18d9ac399253e2de52dbc6e9a9b0eaa","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _required_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n\n# Upgrade from v9.8 to v9.9\n\nThere are some small breaking changes from v9.8 but you can fix them in a minute. Here's what you need to do:\n- initService call: change `Lib.Config.transport` from `true` to `{ handlers: [] }`. If it's `false` just remove it.\n- replace `import * as routeTesting from 'micro-kit-atlas/testing'` with `import * as routeTesting from 'micro-kit-atlas/testing'` or even better import just what you need from 'micro-kit-atlas/testing' (usually just `RestRouteTests`, `restRouteTests` and `RouteAccessibility`)\nAccessing transport.queue directly will be removed in atlas v10 so it's best to replace it with transport decorators. You can see it in action in activities-service, dev-panel-service and contacts-service.\n\n\n# Upgrade from v9.9 to v9.10\n- add `@types/express-jwt` package as `devDependency` (`npm i @types/express-jwt -D`)\n- initService call: add `routing.jwtOptions` configuration.\n    ```ts\n    jwtOptions: {\n      issuer: 'https://issuer.com', // issuer (array of issuers) of the JWT tokens\n      secret: 'secret key / public key', // secret key or public key used to sign the JWT token\n    },\n    ```\n- for integration tests use\n    ```ts\n    import { mockJWTIssuer, mockJWTSecret  } from 'micro-kit-atlas/testing'\n\n    const config: Lib.Config = {\n      ...serviceConfig,\n      service_health_config: false,\n      routing: {\n        ...serviceConfig.routing,\n        jwtOptions: {\n          issuer: mockJWTIssuer,\n          secret: mockJWTSecret,\n        }\n      }\n    }\n    ```\n- remove  `Lib.Config.dynamo` and `Lib.Config.elastic` config\n- `mockTokenData` is now a function so yu should replace any `mockTokenData` with `mockTokenData()`.\nIt returns an object with getters so you cannot use `{...mockTokenData, uuid: v4()}` any more. You should instead use `mockTokenData({uuid: v4()})`.\n","readmeFilename":"readme.md","bugs":{"url":"https://gitlab.com/globalid/core-services/atlas/issues"},"homepage":"https://gitlab.com/globalid/core-services/atlas#readme","_id":"micro-kit-atlas@9.10.2-alpha.1","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-4eTgtSzBTd9LKQMqUR9rhEbgZSKFaD4eibZoIr/xGXuyX6u0xum3rF1cn0T4cETj9KG3WfHuZn2RxuDkgag0jA==","shasum":"5e9bf7ed00da73339ff865e618fa9dbbf8d9fb1f","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.2-alpha.1.tgz","fileCount":182,"unpackedSize":1327123,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgWJ+mCRA9TVsSAnZWagAAGDAP/R85LRH5gjNFqSFJQGxE\nzYFxpZCGnma8pWimf9JfIyu1ZSb+3R/9prC6kWDvNr4qGSMx06iH3Rwlkkj3\nTzOxBEHafY1sMClbC+ARbTkdDFid+fy3UTqi4aWhU2wdK/7wdIwkIPLDZIPE\nWXZ/9/bfPmIhoImUlPMQfp9qftEq7Q6VjIZpnNFGPtwLv4Qfdq7+kcjNkPrJ\nTXzL/sGr8Addi0x/6tPv2/CYsQJVTUDKhriMax3eb3LAbku6/KOslnZemj9+\n1XQwBQUzcWaQJfgKIQxotqxUmI9xTSm0BE4/4CCZbbSB8rKc+Lw4WqQDBelC\nlHbIWCU4ICUTqabfF1TmZnKiUi55PFvdlWFinfR6NYycirDDLAhHTZp1Hc1x\no6ij9kTCfpt1ZiCPkdo027cKKrYZsE2t41shoDRZmOXEwuZ07VaJdk8Bqa++\noSDK4+rvf7ybiuNYQtRY7rSEbtRChP+6tyum9oSaVThqZJJYdJ+m0X0GPd3m\nBme/j4ym8aXyqei9IvUStmauQhvhBQ7R8oWp9lbuym8Ns4oSOI9I5f+KuFz+\n5e3/1T0nXsboqfG8ErbdHhwpnGqERm5noLbqqSCMHkr6CluJ6NkOWdgkKLlt\nWSrnoBPcsjihZkwc/A+paQ5aKa4d/B0WPp1XjMmO61EqqlO9qc4HrhRj0C0d\nWaj9\r\n=Y+9j\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDCETQRuYYcAPOO0jPWRX1GX1dJFvjvjGtHrkaueBZyFAIgEbdAtVxqp/DnfIvjAqg99T0LOpObUe5ePEWfAeaYf5s="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.2-alpha.1_1616420774381_0.1754029694096586"},"_hasShrinkwrap":false},"9.10.2-alpha.3":{"name":"micro-kit-atlas","version":"9.10.2-alpha.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"2fa2339ee358f1b71a30c015909ffb64e289a90d","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.10.2-alpha.3","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-b5AhblOkGahalG725Mn5Tvz3IbxLUO/NkEzyTX3i1/IR/vvstDsy9f8VP+slFpYlvrUNuVhf+YyhQOlfpW7HyA==","shasum":"4c5c17ede8f6fc7c018f1c8823a27c490ac38282","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.2-alpha.3.tgz","fileCount":184,"unpackedSize":1336230,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgWd5gCRA9TVsSAnZWagAA1UsP/Rd1hnO8AQDnLVxSFGCL\n8QGfYf2vp593p08PojutZKmrulO6hE1pGTdmN06FbEqfk5oamxnWIU/chdQr\nzLZZ8uI/hgJ5Bs0EgeHjawaGWIQ3aixfyre2AlUDlvd9aixCjnyJFueMer3o\nVu5yDAld7ZTsEwsakGML6wqr15Arb2raUL7iVgDllmWrTN8w8NLAdDn7JM3e\nWiUCR54RjcwfZw/NSgB46RvZB+8y9MVR54hUjYum7VZTsgd4Cx3ggjjAZsog\nbUh+I0tLjsqykPmuxPineHX3RNqX7hfBqhDjMtNbv4oWIebyXDOrrYl+R/IE\nIujnsLieRbnMtabcmxSVJMTudfpjy1K66dr6+dWQTIqHNCR6phaJe9x0U3Uo\nXw4Rq04d/PsMrA4i4tqx3+U+g44uPuSM9nkCnAbPitJJfleg7dDsYrNmXfwR\no6N3RbKEnP4+H05yewAfrAl1Ne3peooR2+8Q8YJpojign5aWl7EOHIgMg4p7\ncZZT5qcztXg9QeTXI9iCKry4/GrUcZdZvFgGB3QjPSOE3M7+Q8anfuS57oxt\nAvPO4JzANe7PE20obRVUNVRutHt+F3I8eEN2cAtNa5HyMp0tVOo1QQnDT8n7\nmTRYEgPR08qK7sEVL5L0lDDCEhvNZbd0S0VwT2tNJOil8k9/ULZO5y9jdfUn\nWY4l\r\n=FFRm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDTCJXlMdTZQs3OCgcMQsM8pJmXMLG5AbihikJjiAa0oQIgPFFySbl0pGc9wxx2sOyIsWLzKzpIxYJb/dE7W6NbLbU="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.2-alpha.3_1616502367444_0.5540593643632461"},"_hasShrinkwrap":false},"9.10.2":{"name":"micro-kit-atlas","version":"9.10.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"9e3d85138e0d132da105107f4faaf26625c27651","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.10.2","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-7dvHzSN6O54G+dbMC7mk2CcAiSNpXXtxIADZvp79oaQZ75AZFd8Px8oKdj4haJlqFV7ec4QFBDkj9PCCUZ9Ihw==","shasum":"1a18183d29e9e8842f3cf1c793972c48e46cc1b8","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.2.tgz","fileCount":184,"unpackedSize":1336433,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgWexzCRA9TVsSAnZWagAAr/sP/2olxnA7VjVWOOScE1hR\nqmDyVlgaxq9vS9ziwpLc8qyyE1GYpuqGOaR/jikjrOwtv/xpAYPmgTeyjQYJ\nDttFq5K+uJiWgXbpvbG/5YJTPa98K5X30aFm+yQyuMOCQ0ThNVH95nJ/UAm5\n1oNj/DOGZoQh3VbREQf/1kuJiGeNm7mOEq5AG11aelyjXLcqNVt1WXDxHKdH\nA2DM4a1ntF9s7DtTHBc5zKdKCr1rpv5lcH5jhn7O0eeAUZuQ+uS8Cg4NULOk\nj7ghtbIAAQGUZBR8lWyL2OH/RAIObULZNmgnQ65DoEKnfGkKu0RUvw6/qn2J\noT3fZMI3ygW2mTWFjZkdkdI3IyqqwPSE5Yjv735RY7L3gjLYxc+n6KjHU04E\nzGHoI+QBDTw4ZSNHk6qJNRwbler0cafk/FNrL5o9jhbDVscQy3bmQVJUHMkd\nCLDBEmitLNM3MBe9jtgs0uasLt6/YKMzFH89SauiFg6ox3c/OlgnJAUlU21y\nuhjM4vrOlwMzE2bK0dJlVkJ7zEiPxvp+L2sfy89qQxQVn/pkfCBWtBh87wZn\nVp+SPeU/h7CrdcFeLnIlzOQwk62tAcDzrEQtHavJQqq4EaSOaSOnRZLa4qnU\nvCkcf+KKZt+EXv/YqNHylGrjbBkAPCxgVP7FdF5UosbClklWRhLYaD0bTG+s\nzP/1\r\n=Xjdq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGiK4rXRwIpnJAHZqqqv+4uNFoJnDO+uTbAAW288TVpFAiAVQp4GTMNAdUaUzD3M64zXEcoDfv6NrdmpJd6XHtVFfA=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.2_1616505970642_0.5670287063584671"},"_hasShrinkwrap":false},"9.10.3-alpha.1":{"name":"micro-kit-atlas","version":"9.10.3-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"549b632c3061a3f31310ee630941c36d2b32e011","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.10.3-alpha.1","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-nPaYdytKRdzjOW5gA6Awaa0If7uKZh5xh7M/S/33R/dyFEEDvQcNvqrZoUvQjTXeJwnFQRJQaCOzM3u//cvTgg==","shasum":"4f2f33532f7503aa356097dade4cfa2533d2e0db","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.3-alpha.1.tgz","fileCount":182,"unpackedSize":1327774,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgZx4wCRA9TVsSAnZWagAAj4oQAIrqSvT6UvRWZJjSe8Oe\nCcgDSQf+MzFr0BHH07JeuNAKSrQzAu3uq4hoh0Q6C/iIa7usUCTfuufvvPNd\nrISPiffCUuuq8QltK/6cZPxa8PVbZE5T0P5xbsT6G01iKBg5lTmyiIeAVROw\nYBIDaP7NBNgt1/ls04+XRN3H+uOichwimBaHBfdIxJkKkRG325SMbeN67rK9\nLMUF/fPCWg9Dj5XGxsRV12GckueITbLPCcuBiI1Q38oUTBn2OB1dTe1UsQjR\nKwYqoikgluwkOABkp0SWPmPt5cP2Mp8Hes5IJANcb/ahwT+QPwgN9GUVp54t\nFoXMpayb+o8ZDrkG4tioweHNQHXCCowFfg7cl+tYIFHKrFrhfAp9u/s7f4h2\nnjQFs541befbyXnK3YLqmEfmADT96noUtjq028ydq+l6lMJ0zEinv6yXz7r9\na0Bp4Ax5ydyW4+7Ae3kDDkrbHmmuYmZeSXkFJf+gh3udqCnOVVrDyh6bIrYF\n5SOvYXD02lr7Hl/d/7ThEUjf2n4Z7X3z3MD+W2F+l5v64CoWXcZ4irS2aeyU\niL0QFCm/eM2bZWDw4RZKDr0R/jFJCsTaqfTqqKFegDy3qge84EGVpUJRuKK9\nCI/qUEXilbr0UJRa7fIBRGdgaQ3ZqSE418uDflIkp7jKECwQT5iLgHGTRw3J\n0q7G\r\n=sePh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQClRWuMqaG0MHqCeNhw0iekYjvmp8bGwUbReBFTP6W2MAIgSkPf/jzeuwnjZ7NFnGg9PjsDdi7Is3EjSz+8a3hrUHM="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.3-alpha.1_1617370671730_0.13452552846484078"},"_hasShrinkwrap":false},"9.10.3-alpha.2":{"name":"micro-kit-atlas","version":"9.10.3-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"6783c49c3d3336335336d6621998e5db6de3571e","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.10.3-alpha.2","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-LkahEoAVvB+l6Pjcs8o/ngZWyDhDUNp9e95C+TFIo9Y1tB6pY/RivKo1WDY9p+0VAnTl3wOc9ZKlom2bv2mF6Q==","shasum":"38e8bbd51306d369a8e1aa3dd88329bbde50ca7c","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.3-alpha.2.tgz","fileCount":182,"unpackedSize":1333517,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgbVWHCRA9TVsSAnZWagAA6JUP/2y5NI8hlLFtjtPEETpm\naANOkiiNL+oeTdSWAFls3vbIhhhjTmrbbcu7I1vbqvMpERIOXekrK7b2Ye12\n93V6YfrkHUrEo7z3w04NYYGBxLIFJnlXdvPQax4cLK/HU10aDv3m9DZ+i+jV\nhKB32XNCfmvVCg78gWjwdxqo+1CNDYRNQtukN1bIViFZGEBKj4sIP2Vp/R8g\neGUEJRuSXHnOeN/WsQTCWuF1cpG5NPzz1XGOvzI+gzrMC4AoeIqoIEWYSaD4\nFhQR/L0AhRCVIeOaigCpfOiyKUzWnzGtWndfu8iW/xAIwFFPY4tlq8OovUaS\nXOC1IpP6+ybR/dzCHv6FhXXBz4J4b0Z0/hj/iXhL4UEnj2k91AHGy9yE4Buk\nXcYKRsbD3y821MSkRz9l9K+r7aYqO7P5Vm7y35F5Cx4qc+WeMPiNz8RKfvk+\nSTdDlZhdYeLWEq2xpdzytH+UBvhDiSPiSOVelfX3mJXhF+sm6zF8vdODn+UZ\nT4ZvbLJXKQ2+C+/tILF4QUbjLpWK4+20d89xBwGOCpredxN8vrzolUmfbIb6\nFlv9yaaNmC4GC+tHUKXD9Ctui/cMXUePEZDK37wu8ecxORQUw2Q1fbtoSHk9\nqfpbkFBbfrJBdDelTCDYacsww5UCmzS2GFg9GI+74BNQKGDko4+YvRYS09jT\n3Lxo\r\n=INE9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCtPYE6I62R8vEhi+1RuMeOc5uaRTpBr4VDr3bHXsE8HAIhAKgF0w98RlsGl0VSfvWucByPXTE2VL23aDi2vJrPU9Er"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.3-alpha.2_1617778054870_0.8971816335372198"},"_hasShrinkwrap":false},"9.10.3-alpha.3":{"name":"micro-kit-atlas","version":"9.10.3-alpha.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.28.1","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"b60cf29166d48078ac76580379519f519b6f9ac2","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.10.3-alpha.3","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-rTrQz5G1gWShxKqFn7Yaer/j+0D3pEUT4AUSSJ9JUAIVPR2c1xguzwRcSq3xbrbO8N97poMVD6JTLSxIWz2EGA==","shasum":"4276c8fe61e4913b613e28ae22e4a86071cc0ef2","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.3-alpha.3.tgz","fileCount":182,"unpackedSize":1334710,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgbZSDCRA9TVsSAnZWagAAGl0P/2M0eUB3lI34uVMuLYdT\nrVkFOA82bIkWYCllRZgscESAF0SjnuT5slP5TH3bFmk1I+5OPB4C+rupML0f\nuDfZUmGoUMw2VgiMeNUBgMt/uaWSwCIZTKwR0TuH8+WTt0cSzuf/3QkqLSl3\nmnq9C8brNITsRpdoftLNG6v/tSDBJWZc0aOnypSJ2Qnmv9PnpXFws2WVyGXE\nez25gkNA0VXwC0OfvYgyqreYxlpM5vPIwMk0THn/e9KqOUOb/zP4/C6IoEO5\nfqfzSYMr8Ox2c7D9VzbEnUtM1JrMBMgixpuL2enePF+deCtFimKldmJsPYCm\nia3C9WCy2d0UMYVED0UbOldecz/ufDIe5HlJ+sQEJ4y1QDvdzntaRLgl/M6S\n0dTJ/bJvYWW2PusskZeFJPoXEzmJGm43TdwvOZ0Jmmhj/6uy4hXqRiPUulGp\nhJ7ypd7kU+zjFCebbpssDf21lNktLB3t9+r7SNC+eQ61KaHLEv4ishGboL4n\nPW4PLODoGOjUuoK6Pb5/PfxPdTYsgm7rfdzxn6VEVBN3mVXRKjlY4Z6oxBLy\nrN9qvDouaHA2VdPC7jg4943xZ3cvx0QM1KV/PqrUdAATCcmWHJdlSNlLdu5S\ngJKJ5s2ueRg612p7TIRaSDji+Oewg5cGyQbSyyeYHloZH0cflU3wJ+mtJXYQ\n6wYX\r\n=+0Hc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDKyhWKcwhc5TszwGLSiBpvXd+BlISjmk0QkpCVgJ5apwIgaLnnyU2wq7yxO6CHqPP1At0AX/LVAq0ypJccDeiWUSA="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.3-alpha.3_1617794179253_0.952820710579976"},"_hasShrinkwrap":false},"9.10.3-alpha.4":{"name":"micro-kit-atlas","version":"9.10.3-alpha.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"09d9bcce7f64c45ba3328904c72afc26718c9194","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.10.3-alpha.4","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-/Z8Y09lEHxgRbYHMuVXvcXKhUGkequr0vb9uFmN71COz8BnM8hyOpqmqku8EBNWXEaa11+o4b4FUCnXKgvd0wQ==","shasum":"5ab1b6bf5e8e8114d2182fbf22916dd2176f92f0","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.3-alpha.4.tgz","fileCount":182,"unpackedSize":1334710,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgbbGACRA9TVsSAnZWagAAkZAP/06tUAefOrGnNggI8q1b\ncKr6P3nm1dpOmjzu5npYwtwJwwdra7W+mjWhxZKGT6nBsMTmKX6z0IKHbxQx\n/4FwGiEYmfn2FA2G46YVtU6ArsFvD5Np50ahwFpMy7dcqo5/0RM1M7J4Y0xJ\nquUbCv5IOCnyVcjN2cYQxeOXA/uYQr8nSnDBCH8tSv+eH61rIt8KwsSRA1PY\n2TPGrllCj2MaTIm5sZstV6jQ5mXI+m22So46Znwqvyr6lQdDPnXwI3ehvvPI\nl1cSms3cgcH58sQxpQ6EUIVS3AwEp1fsfEJBqgeoKsR23Q+aaWwh4ly7Pu6R\nUbSgMPf5rgb+jzGYclP6pGtU5fTlBJQoujSPo0fA3wgXSLLPKTA3b67w0gfm\n5udqcOSni9qL1iMkWbUDoFY/0KCRGdIePPkHeevQ8sDtaP74W1u0rJXVwun3\nbJ+XObZ7n1L9/5PfWsGrLbJCN6/3dQhASpw1edrZFj+4Pt6W3aemfXsHs6Me\nc3XjPvzCvDPgnwUTMKYzH6j+q5ue8RJ3rbnh6zRrwO6hnkIPZR6yXERlupnj\n20eljPrH9MNTpBDGc49+vpdHX2TsdqSw4qiY9QfwMQjrpUBrVDzrXgewtACV\nOV1mNCgSNiT23NHXuusheeHSC9wJeDq5u0Nh++WoiRxIJdnUMBIxBiO4uCb6\nmClw\r\n=BqT4\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFWNXKhtIvgnGCo0h1HDgZZMntiouPDFw0vxdHlHKDW5AiAmF3OcIN9xjuwPlJHKLHRvk/M9KJYo1rRf/KRsnKXZow=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.3-alpha.4_1617801599215_0.4054210060153369"},"_hasShrinkwrap":false},"9.10.3-alpha.5":{"name":"micro-kit-atlas","version":"9.10.3-alpha.5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"65d2d5a54af12c201ad93cb5b8aae7722e0b20e1","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.10.3-alpha.5","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-9R4bw/Iy0CU5SATURkhmbSuzluc7Vkec0FAwHXhhlUBZlx/tq5dwfstj4H1ycqSaIHycUOP9yjdU1x1hFn5ilw==","shasum":"8b196641a4a75a0a48b406ece79bea7d50dbf9ac","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.3-alpha.5.tgz","fileCount":182,"unpackedSize":1335693,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgbsiGCRA9TVsSAnZWagAA8YIP/14QLwCEJGvgLymmvh//\n4SCQaboQ/WPPjFFV65dYJs3HMi3zCHgttPfuuwQIhdKCv52hrb2KgmVKGc3V\nnUo+Tdb9+zyBpfqA1lAFjT/N85oXnhRQG/Maz9VurJvRAhkI9WZirSZejFuR\nPdCFHCBDsxTME19aMxNS1sdXgSPOV+zPrK0aLl7CxtFr0eBEcB5ubVttyAno\noPrD/gtohbEB0bzr74ObjaEoa1nBUUx0IA4yLql+qNt2sQKevrQZM8aRkfSy\nFwf2zGbKl3/oP7SoZkjD2droP2JycyI9ldwGkhCo3uA9BnKoFE4FJBwrxUyL\nvm3ZqeW+eL7GV9zdll5xfLpwqtWflqwHh6imDr2z9f/kPGA26ZRXDwto+34i\ndR9s3YamVn8AJ+gQJby4Vuxa2RaEY9dGF4n+R8nFbU+nP/EneIxfS64H/rnE\nnxv/iaNhCjxJw7H4z9oe3cxNklj+SfSCXdBL49hTzPFYOH9S6hXe4vfwNOj3\n4mgNp1yi70QZyskn8Pml9E07C9PzIYplLPU1Rjd898/XaUSwHPNPlweluPIL\nnob5xBNIJCIMqGeHOX2Hi0AVKQcGiazGx6h72DrXI2BUIz1fNz/kP68CQ/70\niBWRUMViw8IbxRWlBbCwy1XFTemAu/BMlBxyZk7mfjVeXgO17igZahhkQCY2\nA7kx\r\n=PePm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHHxKoEcR3LNtszZIHfZA2sJAKFfeq0FMg/OWLGWe/Z5AiEA7ViVPdJ+e4RgXWreEKzJZTNgr3G43ZXzQLiQmil2ELU="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.3-alpha.5_1617873029544_0.9695912571944538"},"_hasShrinkwrap":false},"9.10.3-alpha.6":{"name":"micro-kit-atlas","version":"9.10.3-alpha.6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"65d2d5a54af12c201ad93cb5b8aae7722e0b20e1","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.10.3-alpha.6","_nodeVersion":"14.16.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-SfsYXdZH58ajeeuAWoZTvZpcROZR9QuCNXwg7S/+8eqZ0ile7t4pcp6HPMQHFodpmHH6+gZNK8GXykmx7+AJ3w==","shasum":"fa8764be8078a18dd2c3ccb8a0b886d78d9ebd7b","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.3-alpha.6.tgz","fileCount":182,"unpackedSize":1335693,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgb/cQCRA9TVsSAnZWagAAif8P/iIfh5NsUIenK0gFH565\nqMcgI6cUwcM7rtcgZej2yJIzkAqaUPHrLoSpmLNaJZ09aagpLZ4qUq3zaH1z\n3iuB5PMtORf4ccbF6RHkCZC6PpqdB81HwY731wwZ7mbRMdeCUfCI2oNTy7Jf\nCUEoNJjWBb7fW+dmrphB5IuUmjKjO7vQTZI7v9BbH5yz6zwGVbi1RTv0wwtJ\n0HM1BQYjfx1sbbf/4GdiPDAWXEbcYPxdqynSHcCRbew+9HdmqevpXuEyNSxt\n32jw/uP9p6NI2WPHHX8w9j00dU1AxvRsBoJLpvwEyqdQQ2tEy07aLyFvnIo0\nCya/iZvrMqkKhimV/oeyeh8TikALwqsIKYk8S40uy0SClukW3jot3ziws5MP\n0IVx/CsnnFM2B0scJr+iLQCRxyoIbWkIQUS8oXI+RllR1FYXZewTkKm4oN8j\n2p1E0hRzrySCnfzG9wWposv079Acn6sTEbRE/091Tw3owBE1BE4AbmZE06VA\nIDG0Kt/azCRUccZe1dJlS/l4xZ2rkD9c8XYciAG3NermXEbNklYvbwLCwuw8\ntf8wtRIJw2E0t8grjKwJi3kA0O8Tpme/gNN7Bg8Eg62hmCRftFMcPiYfI8qP\nf82liHPgDgcbht3MRtHMeMsGnnjsW1hdRY/X2EC/JapvSQYrBeuqUYtpKJIt\nJKXQ\r\n=l/qv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFA/8ekLRaGDuMxqAH+X+Yu3SH9lCv5cvqe8RzjaxFKvAiEA6uQ5s4cwbEZWiDcRHJgGapOKmqaBAqNgDEV1tfgwrBc="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.3-alpha.6_1617950479848_0.9684433128974141"},"_hasShrinkwrap":false},"9.10.3-alpha.7":{"name":"micro-kit-atlas","version":"9.10.3-alpha.7","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"651a82265fa39d632989e8f35bd0ef270b37b7b2","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.10.3-alpha.7","_nodeVersion":"14.16.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-RJAKr0rPoNvfbYoKLeM9NkHgLoZP60rR/r/3gEI2ppjdk1bTm01uTZdtFRbFL00/LHqItSvtg2EffBuqFCxUOw==","shasum":"fd831c542ad232d77bebc8b77677d81bf3fcd840","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.3-alpha.7.tgz","fileCount":182,"unpackedSize":1335902,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgb/dICRA9TVsSAnZWagAA0q8P/3TRM/tlLfmnVztYkvlP\nbXgj33Nif5g4JcPZUSbS5bCWCTcsEh/5JXW3ArwTsOvKPWmfpuTHWideNaHg\nqer7/DS512LNRmfcvw/Rg016xVEv2YCb++DkOcI4W/Uv1Tg+K5fCXMJ4naAA\ntMuxLiFNgznF3Cn0cHaj+XPvFU94rG9nF8gNgGpjeh5A1N+vdbHUiW0vLnK1\nkgTpDF/RV4G9eAe4NhUMXLq8xMLs25qVOrFaP3uyCaHaLObAqD5d22zpaOEy\nxPSVSSUB94IUk73Bfpawh15n5oEyS4yTL7A79lf8LxC8mBkzTolQevXsYMa5\nto0lKA6wdbs/UNs7Tp5PvjmR3kPZ9D5XbD+Ouxy9qR/nRIZcXyDkjvbmOles\nNzPoBUqkAUipZBgT07oomZebAEpeBWlZwsDuR5FR1tIRu2EXe4bxS+712Nkz\nCjy0rb5j69c2fQwsvC3WAL34kR4ExfuvFgF26LEkiN2e87eroMVumxlS6oQc\nw+KaFeYAJfwEKE19LbdX40vEMkh7o9LYXZivB7yLzv9GM+6UEVd0JzFT0DE9\n6nE2KZWSq3xKVGPO3PHfFNgKg8BwgKMvZKVf3bK9lJ3uQl7TaBvchI9Iu3Vk\nXIRTf9msrO2K3pykLSjOTEBn00xEfPl7fJuLZsyuk3raQ2oIf1OIzutEHi6a\nCkpq\r\n=XUUi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDxZqS1nWh+L1rFwumlVdOn+BmfPAROdL1FZuVDVV5B/AiEAnEO8jE1D1F0w5C0tzDFwCAb1orKO4BM6lrVil7qDqC4="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.3-alpha.7_1617950535975_0.9611892176725452"},"_hasShrinkwrap":false},"9.10.3":{"name":"micro-kit-atlas","version":"9.10.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"dc2a81a9f1cbbe8685a6f66f1afb0b821d3bb3d4","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.10.3","_nodeVersion":"14.16.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-8eH39Lyxxwn3lK4Zy6yd5hcfJjMoqyBfWUg+mU+bE/3wm1AUXYVPz2BOPqrlb/2lgL4VnQuXq9L7cXpxjVzZig==","shasum":"2fead0b56f8d13ab127647d0db52362cd3292855","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.10.3.tgz","fileCount":182,"unpackedSize":1335894,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgcE3hCRA9TVsSAnZWagAAJb0P/1OhkzKrlO8U9zBQiynU\nxJGQoOrxq1LztmCvrXDD6c6W2e5LxwpPrJ0daUlFnsMQf94MPJwYFYwfwME2\nZQOnHt+3HFsF4xC0QuU+/FidjSq5b9qeX5w6siIYo6H+rYLQZrzW1PK9Yo2D\noUY3alGJtrC6POfUvQqRLAUaSd8ygXNbVJ4Ap07snwC+VrA5ITIFrDKpHzDy\nGZ6B0Kg0hW0+KFRMhTT9z0x69CM4Q8kQxDQ8q50RoQrCunSewNJQNN2k8Q0j\nikGFiNY3xClJB770FtjaOvdFpWWwd2RnSCQQ5n/R4yNimBThcHe1r9Y4tdRg\nFUw4hie/paLHNsKtcjYpsUwVZnMYeKBzTcklS1KjQOD1mlNrMFFufX0h1iQI\nMlBtd3IslPrGFSS1S3++DcARsTDJm6cd7qAfhdoFYMJRVfrzYLWF9IU0gmwT\nd8ajAVFpBw+ymvh0O6XlPIq10AzssK0HOZ1Ckg7sbaQFi3PsvxTkUAzO50W1\nmJSOTxcDWhMqKsyG4A17ptX/5Jy86qRXTFghz8DAZeqGNq47j5C5CvrTZcUH\nWCy4FzdtPwYC+7s7twqRI+dGEtgV29j7DbqPNbsKayMrSTQwHssP0L9p/H++\nevPm4UQVr/qNHMHuZSGHf36NcP3San3Ydi8csvGaBxdKFUdGUB/WOgjG0aLt\n6H6U\r\n=u3ua\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGbI9GeUBsSygpiR684LZM7AVP+nyuL/yJwsYj1yD0l1AiEArFRZabkGBLu66+QhEWiLWOjlrCWlCYzH1YL06coBmpQ="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.10.3_1617972704371_0.25432439497946246"},"_hasShrinkwrap":false},"9.11.4-alpha.1":{"name":"micro-kit-atlas","version":"9.11.4-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"2c9425b6456e027bdca74f0ddbc963b52e9bcb1e","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.4-alpha.1","_nodeVersion":"14.16.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-caXAYY28pSf4tf3FSIDC37dTcXlYx4NToH2IiqsjQLqialz8/AUSyEjRLrwRy7kDgU4LCV1vFGtFg0sqrEsTHA==","shasum":"e8ecb936bf3ed624f954853c5afa6c88b7e32db7","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.4-alpha.1.tgz","fileCount":182,"unpackedSize":1336270,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgc/xKCRA9TVsSAnZWagAA8joQAKQ0wadmhegk+RdGk+r+\n5/upj7HMyjpQBwjh+xxRpq9wehza8AjZQX9+8PajpFTVyeRv1Ngv022FZd4Y\neoHGN1k6H36DoCL0gxJfu4oIaJiyOwx3TdPWtcDnutAr6WlZ9s+tzt+OxvK1\nmx/QCUMHtDWInMKKU6ve0ctIYogdbO6zY6fu9b+le6ITrKtcQmcOwVPGOjdZ\nquBLoXiEZ9dmaXcB+phEjupprp4e9UglyRfUt/aIUsGC6n7oQs7E0VatqpAX\nQAfb7iL9r+IiTUTGf0z5kZ4iS11enWBTzycr0uw823cPkfkSyggce2PQSKwl\n9DyMjNTF/UJ2FIpyea+3URJlAR5xizHz09Qgcr2VYMhLJihMg5iJRJxP3+H3\ngvc5ZAPEiMzNwS6MoC52awm+Nmp7Hje8crtWp3/uR/zLAJIF368BCBQ2YTrY\nxOynttXJyrkPXz6IWlGZjq3xorrfiGDTn8ZN5IMqkoa30iExptXwzMrAMg0s\nCkScL43reDtPalkFjj2He8VkvoDUY2D12FecX8/yexw8MreDUOP+GB6SjiJo\nVswKHNxrMa0FqqWC+LliKLhUCo9BrS7KtyfmVGsSav/gp7rsKv+UxV4Agerm\nFD2EOFyXSs45HK3sLL1FHNNOrDQxt3xrUS0RTvrOWgWnx8nbCfKkQowycStf\nL5wY\r\n=ffPS\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCFku4K/hoVoc8vndZSdJtaAfuo26M55+Qil8xy3eFF2gIhAN5Vt3b9GCSmMbLrmLBwjbRfV6ExnuwCu029gOV1gl+H"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.4-alpha.1_1618213961979_0.05167439403782814"},"_hasShrinkwrap":false},"9.11.4-alpha.2":{"name":"micro-kit-atlas","version":"9.11.4-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.14","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.19.0","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.0","@types/lodash":"^4.14.167","@types/mocha":"^8.2.0","@types/node":"^14.14.21","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.5","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.10","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.10","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","chai":"^4.2.0","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.21.0","mocha":"^8.2.1","nock":"^13.0.5","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^9.2.3","sinon-chai":"^3.5.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.1.3","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.841.0","axios":"^0.21.1","class-transformer":"^0.3.2","class-validator":"^0.13.1","class-validator-jsonschema":"^2.1.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.0","ioredis":"^4.19.4","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.7.0","qs":"^6.9.6","request":"^2.88.2","routing-controllers":"^0.8.1","routing-controllers-openapi":"^2.2.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"19ac18d56616863b6420e269fc2e7b48fe4d5d59","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.4-alpha.2","_nodeVersion":"14.16.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-pZ/QZuRUGPHOKkCB5RnvasI55SfiB5sjF/GKZSvXcs0rJaDct7K4V98ZnRMir0A9XlSuB74OCw16nT73Yr91Cw==","shasum":"a76b8d0ef46478a6f28438809e7e8e3f6dbf2601","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.4-alpha.2.tgz","fileCount":182,"unpackedSize":1336325,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgdCZsCRA9TVsSAnZWagAAK8sP/0GPb/LG+UAQICgYaUUH\n1zlvulYFpMiGF+uDocVQAZHoBEdmV9xl5EgWlf847mGFM+3dyurdcM8gH00A\n/ef/SYw/fWwnlUJ8BqUHreTEelsYZns3vriI5LFLJPe1Y0JKybSkz58teQEL\nUo8tzHZ0OEsi0qkancDPvK28GyFmYLfvZL3gQH2WSZrRzB0PqMkzX5wq4mZR\nBSRQZcupYOsRb0wVEolGQraeIu8HyDyrSQBGCDV/+ma7W+7w72WdQcsC7xK1\naBPih97P4oYEmmxNRxS3odp11fWq+g1YqJxALetUR3hwegegUrr/h37iQcc8\n9tN8+rQ678zEw0sRUbI9vphsucuUDhw35FQYQNMDYDPTMqyIg6viY8EhI57I\n6fDJFq1crfH68dRQ4pQXE4kwTuaspRRN64ev64f+mxQQ2i7VblmFBvfUkhDh\nmzmsFQ6AEkRDhTiLrdVeKZix79+iL6v97JEM9KM+Q5CSQJa5MKak6sUMRnQj\nH3KoezTI/QTIFJTlqbjX/izFkpJJjfGq9oI29hYseN1Te6ZG8SapN99T/hPf\n+qQmxsDQvlN5llLMRUvtECL4c+izDr5VBkNi/a9mPaTgTs/i1GQTKHsmbsop\n2DBXu3NWdH7P3ouML75GVpw6hMrHgj7w4x/PizMGBOF/OwXVA1mZUUm/dGqB\nILbD\r\n=YT8R\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC27A7uDSKANpsv5JYPR6b3YT16DEUmU3JEUhcxVza0BwIgH/q3jIumF6ehk3yBC6r4Mt1FEV2a7KUZwSkv+C1vsBk="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.4-alpha.2_1618224747497_0.3884127565087925"},"_hasShrinkwrap":false},"9.11.0":{"name":"micro-kit-atlas","version":"9.11.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.16","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.22.3","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.1","@types/lodash":"^4.14.167","@types/mocha":"^8.2.2","@types/node":"^14.14.37","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.11","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.22.0","@typescript-eslint/parser":"^4.22.0","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.24.0","mocha":"^8.3.2","nock":"^13.0.11","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^10.0.0","sinon-chai":"^3.6.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.2.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.885.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.1","ioredis":"^4.26.0","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"602ced6acb5744fc9817b0f0f2c7fa0fb6326248","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.0","_nodeVersion":"14.16.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-W5NGhRaaYbxwu9txlnmPJ3gqtXv6IEpH4cTM+L83a9HfqHrol+n2yRQ58j/kc8vhC62emD+sJebeGTm9gM8/jg==","shasum":"ae60313b4d38b33ca1bbcb01b096ca2cf196091c","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.0.tgz","fileCount":188,"unpackedSize":1357644,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgdrsbCRA9TVsSAnZWagAAKGYP/j4dmxDh/QHEJqheWxST\nBp59BT3ObbUUFbE93nYsbHJ0VtJjonPcKKfYU2/JTcFbO3HSkymbr7GcDDb8\nAavCoSUGtD5gNzbotnObPpA9xdQrv4uSYZUcls3fWeHkWK54sbmXmRfrQO/U\nmWZ+VtgWQyxEiETbRWTvupiF5QJJRmxSqFiURf2FAga0aILHz2LGWcxfzAGa\nsUzuJIYX6jQrO3Mqt93l6VGV3AFTFzytI+1d7rrN9ljSf54fhI9XzY6b6Vl+\nW83jyfSGh8u329Qb1PXT+y6Pmj41X1HW8LsTrWJMQ7CFKgP0Tego0zxaoLrW\n3QWIJ94KBMJdg9yFZzB/Q1zGzjy6RtV7vYtZZ2Z73FlZxja6/4N43R1U/NFX\nS4BVFj2KyBFcHNiWrjXlLbB2sp/F3W3Lnk3cakqIndc1boGNPyAQ6G7sGqg6\nmzLwmIqO0Qmdm5YpfEh1g1hFLayWPEg/2Fe1OHS+E2UN8kXcZciUgSjzInBm\n7iQY2OE0btKifzkGwHYSnrIKBRo3QsazrpOdG90mIkVmzNvPaO4FcIQA1r94\nVID49c0APMzWUBZVb5oShlxKbeC0H9EBeb9iad8taf1iL1RFOUtw5Cp+9jxk\nqhWiOb6mEst9AX62mz+h7ntpacF6IRtA5PFu48hzI6sDLJTpU5id6OZNyf6E\n5RQn\r\n=VhlV\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDdjVwWUQFTxdxUbsBOtCcU/YFlPTj//N8dy1cFstVMkgIgI1seeii3jXGd8QjDjCnzVFbr5/1m+/NcK+Eyljldm5o="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.0_1618393882571_0.6585382453370738"},"_hasShrinkwrap":false},"9.11.1-alpha.1":{"name":"micro-kit-atlas","version":"9.11.1-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.16","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.22.3","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.1","@types/lodash":"^4.14.167","@types/mocha":"^8.2.2","@types/node":"^14.14.37","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.11","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.22.0","@typescript-eslint/parser":"^4.22.0","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.24.0","mocha":"^8.3.2","nock":"^13.0.11","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^10.0.0","sinon-chai":"^3.6.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.2.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.885.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.1","ioredis":"^4.26.0","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"bfa7ff806c172af9a9163705b6b8e34915141217","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.1-alpha.1","_nodeVersion":"14.16.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-Wlpe/Pn75Gc4F/O2sbWG+MgXqQwhrOKYFWna8+rVh5xMXhfU4usD23GdhPj3dy+sjEhHSfLzxaHtnZXo8Me7Jw==","shasum":"dc4c176071fefb165eda301529d899cf66458279","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.1-alpha.1.tgz","fileCount":188,"unpackedSize":1358220,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgfn+lCRA9TVsSAnZWagAANPUP/3rFAMA2DYFqF04BEIiZ\nJ/RANZDmg5kWkt8bKUkxgsXfGaXPVxVyglYmMszjamVicNXpNrYavC7SzYM7\nHMNAyWZ5FeedttwZvwXXvc2R5aHCKg8no/4jpUGoh78zo3lWpSWvomamYNCN\n0lvvMrxx8wjCI7+ogwJ6AZwcTplJnVhVCeDYgC5D/wBRTpg6QDVSCjnC2yrd\nbpkcOJz2kjsOJVN6/K2xSDUv/AjTPIeOVH0KBwKy+sUYwTaHKnPU8XhWWM49\nejJZErdvMiilziJajQbSKhHhoDUjT2RbprCCgwsdSgYmVnCUHWkWFP5o1Epo\nKuEI/L3B+Cd3mFiSkPD6S+e8LZkTsMAEVrl8JyplYmUIoxDh+Phh8zPG1bAg\nkKXem0EWtt2AUPWE3eN527bchfJCTPfLxpYvXqcKd+ZOjavK8N9oKRNGqcQh\nPjrc2mkGuhveE8Pg+j8LiL1Wf24ycZ7RuJLwnmBaMZXZ8J65VL4XJzqIb8G2\n7A9BKzCgvUTeWMCZQ1r2wGm9g3IBZ6kNVJExs0Dln/b5EGt+48KyDFn1HQGK\nakj1ig2c/G3PGsi/YDK2ivS2Rf5ZS9lcbCBF9RG5CxvePfJRnZRU2GafSxoX\nDbTn2pbUlRR62TBk9mP8TvzR/VbEQ0Pg0IcK7rAgyWjUrRa6Fy7f1mRU7lU3\nZmDf\r\n=+ALd\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD16fHwgleLPqSnJPo+X7h10svg1uwanaslYCk0j2+obgIhAJEAe35QDJF6BpwLmbozF31Ygf9oF3Jb7f2aq0IVydB5"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.1-alpha.1_1618902944766_0.8594213755800264"},"_hasShrinkwrap":false},"9.11.1-alpha.2":{"name":"micro-kit-atlas","version":"9.11.1-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.16","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.22.3","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.1","@types/lodash":"^4.14.167","@types/mocha":"^8.2.2","@types/node":"^14.14.37","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.11","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.22.0","@typescript-eslint/parser":"^4.22.0","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.24.0","mocha":"^8.3.2","nock":"^13.0.11","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^10.0.0","sinon-chai":"^3.6.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.2.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.885.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.1","ioredis":"^4.26.0","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"f8a3c688ca4909526b146505d4487324377ec492","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.1-alpha.2","_nodeVersion":"14.16.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-3dAs0mU8gH0+yOeK+2qhTov4ZGxmFFCIiKQRE+RDwouJ2TwdsCDOICsqnTfwWlNKVmIp3cYFWw/tC4pY2BSlLg==","shasum":"9f2d0f1b28931b01d0835de01b3cf9eadc09369f","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.1-alpha.2.tgz","fileCount":188,"unpackedSize":1358002,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgfsMgCRA9TVsSAnZWagAAXUUP+gL9+kdxzyOGEt7FFbWA\nd1DS07oTHCXDJ2j7YFuW5f44s5nfOSN3NccMh+8KhlARiUjVrHSBVlq9RkfU\nwlQ4lxKl4c6YEFT8ptbhlR5svaSQc6llZdyJ39zEP3KamG3iHSYbeFEqk3rj\nm9LWDl/qg1Q230xiztoS5c7lXFRyuH0GcIgcnVQR2zTQgLF4h1qarMUTRU5c\nLIhJktJKlKUgCApsXdEP1SS+EnfcoqTZr2sJZbxgyf0hMn4q8zmfT4ep18ne\nwGNgji4HUgBq7XIISEGglKL5QxwkgMT+XqTY0EFadbZebuKtyF8DQgdbp7U/\niie80iXYqfAoBuS34LUSUY++lFaR/+NgmX2D2ypSddhpTL++W/fyjWVbbGpb\nTtaNWYjZ8oe58KI9s7dkGsaL/bjxZDbURQ0C5LsUf9qwnjUnjhCRxkqkus53\nSckZc38fnABp9xKRZcKskrII4/hkz44w9B0WTgfyLAgoIBlIrYOTTYTfpK/L\nJdPig6cj1Q65UDVvJDEGxw1IFFu9OikjYjv/Vj5+FmxqRheMh1SNtxRaV06z\nJ/NVoaVxtCzonuOxGmmGbW7wtTp3/xfKaHMuvMfiCo4hp4mkqIunOpbbtIeP\nPGuS0DaaTse5Eket9YSW47iZLPySiNlln/TN9akl/5utDjwRn3rT0n6OM+lw\nbAEi\r\n=whp5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID5rz2Q+ZwIF1DcWddWyfT6JxwiX634hHaOYS+rCU1+VAiEA0xd4kNNM90674iL5UDb12vYARQTziho4S+zaqW2CM88="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.1-alpha.2_1618920224044_0.9978162736144385"},"_hasShrinkwrap":false},"9.11.1":{"name":"micro-kit-atlas","version":"9.11.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.16","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.22.3","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.1","@types/lodash":"^4.14.167","@types/mocha":"^8.2.2","@types/node":"^14.14.37","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.11","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.22.0","@typescript-eslint/parser":"^4.22.0","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.24.0","mocha":"^8.3.2","nock":"^13.0.11","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^10.0.0","sinon-chai":"^3.6.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.2.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.885.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.1","ioredis":"^4.26.0","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"c203cff254e305840e2c9890c9691d1972e46eb3","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.1","_nodeVersion":"14.16.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-48iw1edmXsvUjGh678iVp55r9MEKsr4GWSn46WH5LUi/8jY1AR07Zpv8AFRuVpz0HMCf6F8HAjsxOba6/Ymh5w==","shasum":"dc1f84ee6c091a0fc3433254f239d31c3f718aa7","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.1.tgz","fileCount":188,"unpackedSize":1358610,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJggAi2CRA9TVsSAnZWagAArDQQAJGtJfGqPn+WpHRqnbJn\ngHMxXsjSIMwRLzBgLfjf0qT2ywiWRrs2GZKA632tUXds7kfpgGCjrHWOWYlM\nFXJgBvK75o96uLb6upaDgW4DkTutaDGFLKDJyPn3cCqajfdHRE421MgpxvDx\n2+03ZukbLJlTgRrBzV2zymG5ln5krzEapGS/EnO43nE1iHrXvlsV0lBes0wn\noaxJv9vJFs/96AQjpaXjhoh8qYDLo02XYGwUvYXRoFrr78DiqPwTKx43gpnz\nPVqZIlpyxQ+uBx0KSjF+XIZFelju1bih83EhcifGy4Kp0+IgIJIsLdutQUm0\nPQRoB8YRwRx1NPoT8FFxfyxyP+FTLnuCGtSCR5vO6aT6eCdXfv0j5TxYfpHh\n+gwLaSJzd2a88KshQ/p6eFDU33utfCkBmKZ7Rmjvm2OsGyvMFyOpwqvYA23r\neB4g0TuYILPDpJvM/av4LQUYDCvTIJJOT8vaVL/JLp5kHyt86MhxbyQb2ctr\n/nnIhspAtIj/+RQ3twYe7MT7GzZM9ol0LFLM0DyWwlQ103ab6dpriFV900VU\nHYxfu3v6M1E1WrnN3pFYW3mGFoc8iuyGEnCQRkuEbWeKH2m0bFu2t6GDvKTC\nHU7MBEFuxbaCmeQNOuKSij1UJqXHaPMG5N9EtIkb7tKy7qduGNd6Fx//Fqar\nawSt\r\n=2Zjo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCBW4qZCA2V1smJ8bGXkR6Bjq0TR6Ym7XPxhVsOcvn3nQIgHz8aC0iDjE/Kjth3vCIaVkXXi674+EQVsDJEAr6dv1U="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.1_1619003574032_0.47262293611554274"},"_hasShrinkwrap":false},"9.11.2-alpha.1":{"name":"micro-kit-atlas","version":"9.11.2-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.16","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.22.3","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.1","@types/lodash":"^4.14.167","@types/mocha":"^8.2.2","@types/node":"^14.14.37","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.11","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.22.0","@typescript-eslint/parser":"^4.22.0","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.24.0","mocha":"^8.3.2","nock":"^13.0.11","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^10.0.0","sinon-chai":"^3.6.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.2.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.885.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.1","ioredis":"^4.26.0","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"0757553d7b0209626d55b6dfdd484d06da8a2dcb","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.2-alpha.1","_nodeVersion":"14.16.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-sTZZ5OxQvvWXAisaMAvmTA/YpmlEvbgXr7z/EAx5psxrdsZDXsZC0CsALFtZVrO5y0vJPqX69Rt/2VvXk0Dj/A==","shasum":"ca52e1832e9fa1dd933260532656d5fa43dba85e","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.2-alpha.1.tgz","fileCount":188,"unpackedSize":1359800,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJghpaVCRA9TVsSAnZWagAAaz8P/RzAyhvPVKvoJ56NSBpj\nBYAcpkxsmFJu4fuU0ucAJWp92s2a0YINONOk73+WHjIXa6Cbwtu3jb2GJJ9N\n/I5DigAw/0w7izuENbXPFDFTg4bfpnDT6DlPQ/6JgcKIt3vXVkAtAwvU9f0L\nRw9QhVecQNi1nL7S9+SnzO2KqoLCOigYyKC1ELl8+nx7BCudI3m3atlqVg4J\nQsCmJQxOTlybjv8fQSI1M44Gl4LHx1dBzHTdzjxkDayrPjq26qz+9e08lUJA\nCkpnjtcpemcbIuBEMTFTWpXLvqJ3GNZ3uTbSvnIrliRjcP8Gjh5vriOnLomC\nOmTr/Q7XZyngysdKtElbwoe64XTXOx6gwkv6MHL/QJ791dvfNjZqVGb9XuNz\n6WJVwWUl57p5CGX3dkCwvqXoEiH5RGAdkkx2gHqoZg+g3dEpwo7so9pqcb+x\nqDCJfZmw0BZFFZ6aqVUNPzKUwFuPYRuGSn1JRXuqyz5WcfwDMz2VFTvMJzub\nCkValMKp0IJTBwsNvEl3i/Rh986bJELA94USCerKWwjSlB4ePDB3O4rJpDMG\nEFpQ3uMaa36BqIKExcpVT54VOedoLnt0ThZFJTq9vYMXQDv7mIoyD56PsKDq\nxcdimVLz9oe1HJWdU/HLCFqMnYZFTB9o674wJVmzpzSv6dJxMAjtHMZHOLCu\ne3H2\r\n=02pw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD9TJZQvi29mzGAw9fEspvPi3akQNOznw2cGrLCXupEAQIgT2InxtSAgGCvm63nWtiifI7KA2sERtEJmlR9NCsCOXs="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.2-alpha.1_1619433108844_0.2512132269784635"},"_hasShrinkwrap":false},"9.11.2-alpha.2":{"name":"micro-kit-atlas","version":"9.11.2-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.16","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.22.3","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.1","@types/lodash":"^4.14.167","@types/mocha":"^8.2.2","@types/node":"^14.14.37","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.11","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.22.0","@typescript-eslint/parser":"^4.22.0","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.24.0","mocha":"^8.3.2","nock":"^13.0.11","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^10.0.0","sinon-chai":"^3.6.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.2.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.885.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.1","ioredis":"^4.26.0","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"a98f04a8f116f118842c7f7c9d991e0f1caef05d","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.2-alpha.2","_nodeVersion":"14.16.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-3U0TA43eICcZbkA1Pm4061Zn+b2EhUzvFJZwPRRbhgUKxXwU+Qoc5m2oblDe1frIfuHik58jdpAOpDngqXbbIA==","shasum":"47c4328fa890a3f92f109c270f287204f4aa59d2","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.2-alpha.2.tgz","fileCount":188,"unpackedSize":1359778,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJghr5CCRA9TVsSAnZWagAAb14QAJbQRVl4oSMoXU8g2DVy\nqC2BlgLKOsaVV97P4n4vYODqxNsocKTWzuZypkkZC8IMUsisEwPLAIX/yfhS\nrYTZaQk2O2plcbc7sfvUnS9Gz7YF/J1ze7YT4YtSOY0pSWu5r2UC3HToYduf\nMeEEogpFEnsdZOUW1noucgwlb8AU+OzBLbNlymBC61ztMwkacP36y9m9Y7oT\nDY6Lx/8aEQ/dGs3PciszOI706PhwkStUMXxcHMhzlacl2CHizFAEJJeQBiSI\noRV5OxEqV2KJXLk1+2BDqA40h3a/XRJ/nSS/K0ZYB+4rTOpb+DD16wUa7O43\nKljkmeQjv9uek6apw8hmrWmb/07c1PRfwj+YjF+eig6R10g1ikRZwWmjGWIf\ncq4DMZNMa6TfhF66K91Y4pNMM/DfXJnHIcD8oRzALxhVvY96bzVcSzcrh7tO\n5gl0KiPvetyDMeqW7sS50L3fdnkSyBWdeb0KXrYnFeYgDWaHxyKor2AIYBi9\nH5xNZKCEziMgevmbVSk23itPUZT6gBNE8Lafrc2D2xL6bV6jvzCFlim6Kfgk\nyEhgkHT+Fui50cmLgEpjG/X1HKJRhAnCR+sa9c0FRG+vxSfYFXcsrIGRWdjn\nnKHTyrncE6sY65C8eXmTDP0okL59ujcFTc66mXYhFaIDOIATNTldKMiCrKeo\ndo8N\r\n=y/9g\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCID4QekIfur/Tk6euz0A1y/FVNKi3xj+N+gXAmmSfty3xAiBhGwr5xi4o56X2cqzsjq/IeK35EyTj7Bv8YU64PhCAQA=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.2-alpha.2_1619443265913_0.10721950556611737"},"_hasShrinkwrap":false},"9.11.2":{"name":"micro-kit-atlas","version":"9.11.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.16","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.22.3","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.1","@types/lodash":"^4.14.167","@types/mocha":"^8.2.2","@types/node":"^14.14.37","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.11","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.22.0","@typescript-eslint/parser":"^4.22.0","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.24.0","mocha":"^8.3.2","nock":"^13.0.11","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^10.0.0","sinon-chai":"^3.6.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.2.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.885.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.1","ioredis":"^4.26.0","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"28d26df70123c0771c92dd56fbf06e3643dfaf01","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.2","_nodeVersion":"14.16.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-JRjFNdWKnwwqLwrjjZOUf+kebGwE3u8QHl69lVUJh34oFJ/gYyuQZcGQlhyvTLliDfpNKvqucRJ7injbC7vqyA==","shasum":"a2f599d96c0f9098e16de4a91218e98355d2cd8b","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.2.tgz","fileCount":188,"unpackedSize":1359770,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJght2ACRA9TVsSAnZWagAAGT8P/0BKjaBx9xbhpxxRCcA6\nfr82FvtQufeq1gm2Mp/6NtEmBZvtf8loFRBIxXDbPErCBHyfej0hnsLAqeV6\nJw+AtUgxEeViMIgtLHkZtf17Mv7ptMsZJa/f3/JoSOS30LtG+WEfxJFeQkRB\nxZZofzaGWez6R8Gy6x0VrWX0xuADd+TUQUzswhL77KeL2+lN7mOh6ZujOwAS\ncEoN7CIptBPvyg5xUUsxI2y/Z1/GOcOYTJ5H+dXOcGQkI7rFC40WKWpenzkC\n2dENaEqIqRbgcAL7gbewYrgqHIANDHGWRWe+LD7sCXX7F6Tvr4iHTAumsnd5\nyWHAyrjdzrxc7IlwjF6wNDmgKuTlJ/kJLmXMv3/FDyDjC8h1/xmFZQJWSnf8\nMEiHWo8JANt0h21awfsjR6d4O8aNsMQvdHOQ8/rDI+vXztgBZvLwlT+mm1iV\n/Q+bqyRvIOaRoT5ZjFF/zrVs1Fz843cR04Dxz1YKW6JnCuu4aYXIy7bCHPGM\nzv09CUfhB7ifn1Js5LWC2Dn9O09X7wrDgzSQX/e5qiqNc2v+uOExlYR/D/jm\nfmAl0gHd0BSZN9wFcKqxw9nxnSfadz5BSabu0jadVeLRdMWvAaJp/sX8V287\nXzLn2Lg1m19aQFFnwxedrSocJVJFmn/HTd/pdc7S1zq+BiBavut8C20+T8UC\nP/93\r\n=UPAQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC7KbEtfkgiYakRd+dUJwzVUPWqw27EFbEtfnETSdteKAiAkE3QqN54meCYU/ARG7ey6SlSz3wwdWHQohV83CUcEqA=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.2_1619451263954_0.24311406267934932"},"_hasShrinkwrap":false},"9.11.3":{"name":"micro-kit-atlas","version":"9.11.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.16","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.22.3","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.1","@types/lodash":"^4.14.167","@types/mocha":"^8.2.2","@types/node":"^14.14.37","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.11","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.22.0","@typescript-eslint/parser":"^4.22.0","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.24.0","mocha":"^8.3.2","nock":"^13.0.11","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^10.0.0","sinon-chai":"^3.6.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.2.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.885.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.1","ioredis":"^4.26.0","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"5c35850ae685bca1a79eb05478ac1a803309d803","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.3","_nodeVersion":"14.16.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-GeeLa1eKq0lU7xIjWH6jXJPWJV/vViJS2qrxE0a/+9YCSqiOzv+Bv1sHectC/jxdMMm+jtLg1FxjFGcjHGS0Jw==","shasum":"88da8aaef198a6d6f669d1803d0a0279879753a6","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.3.tgz","fileCount":188,"unpackedSize":1360019,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJglQeTCRA9TVsSAnZWagAAK7oQAJNUYPX36gVC4GEZ/A5W\nfVMbbniH9DfFrdpOib09qXX0O6wLduG1GhzoOT9uiTyOUm4cHpGjAIxJdpO6\nGwfWgG7cxb8ZAsyBNvWcs0mw0q4X7rSprRTaXOCsowiZOZGZPDGsVsVkYLmt\nQzv1smNWlmPqnXy1M/CV3Yhlj8mY95aAwT5Qmx3iSmkqj1C5BjEi0sbSKJ4k\n0Ds7WcKvnEaGWdccFeoePM9lBGem3El5Sx+i6icAxa2vKC8fbHiO3W0szbAJ\nQFWUDcBl2y1vD25R1QSu0OWhmvckIHAO21BbCG4ll59xeIPKX78mLfN/JOjG\nst2Q2U0CNv61JuOHNSLMiRqNij714WUlaCm20JjUHcKMBcmE1yzLfUrFxWwd\nBJw6wQ3CYwpjHvE5gYw/+XDc+mFBaakTozPAIIstkDjqPAq/7iPU9+2cvjri\naGItnEWvfvVEeS5oPeADMTNC0GeYjAcFFSEQupSQKUgKv4ciOYP77KF+jW3H\nm/nJSc8Os0AN3elE73VGjUcNeFds0zSjK8Js8UH26pW5J3BA+oWi2rZxC//2\no++Sn3tjdsVKADx3geC5ij/M0VwMUKTGTDAq9hh0v/X7r90J6h3HJDJtIgyg\nR7hWcN8s3PJ9ML7qGo/8BcbIlVP1vYclNdrHqzmVSu5LfLb9QnOoBPdMZheG\n10cq\r\n=w7T7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCj+eT2r2KNV5tsW00w1ykLcTLnDXyI2frkOWp09HbS9AIhAIJdlzEzSqtxU3GRAoc+LUeVeKJ2P/SmEr0Iervp5+MW"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.3_1620379538732_0.7318370999953587"},"_hasShrinkwrap":false},"9.11.4":{"name":"micro-kit-atlas","version":"9.11.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.16","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.22.3","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.1","@types/lodash":"^4.14.167","@types/mocha":"^8.2.2","@types/node":"^14.14.37","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.11","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.22.0","@typescript-eslint/parser":"^4.22.0","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.24.0","mocha":"^8.3.2","nock":"^13.0.11","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^10.0.0","sinon-chai":"^3.6.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.2.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.885.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.1","ioredis":"^4.26.0","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"18cb95c730c76a110333a48adfa65ae0a7896705","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.4","_nodeVersion":"14.16.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-nij3ma61A0uKTiKp4NnwcsZdnI3DLrSiotuaIwWd3hBS+QVaf63qY3kvynnoaYnuVJO5icPliU3jghoAt66wGg==","shasum":"6e1a774a495d661a745bd3c4697af9b043b2b858","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.4.tgz","fileCount":188,"unpackedSize":1362639,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgmm8iCRA9TVsSAnZWagAAgi4P/RzTuOxSFzTYzzYg11Fs\nMjMeI342Uc7AQPlV6VshB1bzdYS/UBLT1ysbBSN2x8JXpjKjHXaEN7J2kkYU\nndtNnSz8WxJVaRTG6ad9oTQ/EenhtlWR8PgmPARua3CZnQlVEo/bZ690i7Kv\nDG2iJlI2XEFPUSpfpDsBVHPnNQ3byyPbtrSib9CVEexdYw1oK95u9BGtAIKW\nZQPxOZNu658wZQD7WmAqLrhOXDUFfHIgYSpfmYq4hGJyCqhUaGBQ7beANRM2\nECCqr0knInqi74GjWaJOpzDXSG5lmP2FWXrYV1jtpU8yhLhg1kgOlGCSwpwF\nbCbKPZ51tAgDeYcyvET1iggd4NBc2jXBoolcyeKUb4sjRdIdSW3XI9fTYjfk\nHHF1niDqqei87FvIG0VKl2GSpOXyxNd1SUfLq2suRtzx3MtDyAAsNvrH+Zvf\nGp4so1HnsvH/qjoQkCq8vcIWpHTInuKo7D50iqo5Kk078cFncDil+YC9aWXD\nyARwFfbu0JYEdrUs5oONMrBonIUtM4DSrAK67IiRU5tkXwAcyXtLby2Azo17\ndzYmKJf/jA5TioRS+BzMgFvDgk1LkO1b6J9xHVfGyAc9YmjB3qefXzqlA5Ys\n5TRfhJVecfsVqpezYj9pLDF9xKCXBAsK3SDv3wZlzERhrAK9rYQc0TVvbHzm\ne8cr\r\n=tV5s\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCHOgFWxbzuhwhrFkV5zxtDpfCksNBl0XAYpFA/UcvRmgIhALkGjPsKgKc0K1L9XAswAGcyDFpZzWdaf3WZsWPk6uY5"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.4_1620733730050_0.32391993476703207"},"_hasShrinkwrap":false},"8.1.11":{"name":"micro-kit-atlas","version":"8.1.11","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"5.0.29","@types/express":"^4.17.11","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^12.20.4","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.2.4","aws-sdk":"^2.853.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^0.31.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.17.1","hot-shots":"^8.3.0","http-aws-es":"1.1.3","ioredis":"^3.2.2","lodash":"^4.17.21","micro-kit-aws-queue":"~3.1.5","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^2.1.0","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"f89b7b655898ab5c3bf82dee7e610e9bb33a1738","_id":"micro-kit-atlas@8.1.11","_nodeVersion":"12.22.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-E48KK3FU9bRSm/SUsu3J6GoBfBb+YT4jeVhG+wNWU4b7pDehYfc/8dLiGuRri5dkq/tajGSHI0b6tuV6UuOkNw==","shasum":"de2bc46a39c8a6fc8b38da10c60f38d719255006","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.1.11.tgz","fileCount":61,"unpackedSize":144851,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgpNc1CRA9TVsSAnZWagAAGJ4P/3dGLoNmYoXnGBPGtqfD\ntYRHqZDnPyRvWUN+ZqRnCofSz4dZTiQLQ/hSr/kjqaPAb2LKZOOaqVKRQmji\nhG9BpIHbBX/9icFOK96q2XQ2LeHWxVsggwYQvFrqcDr+TV08dKcoE9JQp5WB\n9BC8nYjkxYMlOY1D5cwe8HvVTuLILLxclM0kPHHgO7Sf0rUUcqEPhxDeDqrh\nFAGr2P3w76JBosUpGSMEbYAZixwUZxh0dFsRoLeCnMdrsk8xUNSWII+1i9ZX\nQOCW0cYfEDXeUtABS8nwKxTnaOiRdOgSVD3/cFQXf++4ortMUjCNMszp1oW4\nOAiip2Y/HwBwBf3FG15OoATGDKp/iWCsQN7Vmwp3F/KUFEGsu/agAIBEe76i\nENl9gRE3tZm2lI86Y5RSUgpnthSmnpqETrpZDy3+eRBKui9BNnaLbZSJbg79\nnxD23UWMVANAuvfRRuCThvj0Us5o3VFS1jFTihBCqh2JxBA6uM9Ta7j4yjIa\njoUy2QyQW6wrwlfsCl/CGbh/gS3qGlN8un32ljyvqDvDzcujyan3AQrFgHMD\nx+4WOg2Zrtxv5Gc0DqsAeFuw42fMWdrRR9t39c/U6yiJ8ZHPJLVGwkUM82oG\nBGvLBcKWQ3/N80GuGd7zgdMxOgEWPhdgBVWMdW8ELsEM+7pwEKwiQAqTiqPZ\nZim/\r\n=OhOb\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDUwQJCsNNVSCtt40VnWa2LRNy7OZQLEfcEIgAVCxgAdQIgYRatcm1NLTNwl1zG17z71b9hOqvTFKxncfBSge59R0s="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.1.11_1621415732802_0.7618152722607203"},"_hasShrinkwrap":false},"9.11.5":{"name":"micro-kit-atlas","version":"9.11.5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register --full-trace --timeout 30000 --exit","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only --full-trace --timeout 30000 --exit","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.16","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.22.3","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.1","@types/lodash":"^4.14.167","@types/mocha":"^8.2.2","@types/node":"^14.14.37","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.11","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.22.0","@typescript-eslint/parser":"^4.22.0","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.24.0","mocha":"^8.3.2","nock":"^13.0.11","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^10.0.0","sinon-chai":"^3.6.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.2.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.885.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.1","ioredis":"^4.26.0","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"b4d5ad6c69c28c34dab0fa910afee42519c52a78","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.5","_nodeVersion":"14.16.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-VJklyeiOf9o3WyUXQTS66tryOU/q4sO/IXoO+ZRsM8qz6NmiT/4PgfiylRPObXwWH9LxH1vkNKzOjpPCwYODzQ==","shasum":"8a3b7577b2a93c85c6825ca9ae9eb88c68893987","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.5.tgz","fileCount":188,"unpackedSize":1364334,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgpNdiCRA9TVsSAnZWagAAsmsP/jumZiUmzZB9fzYVyrep\nkL6G9yTDBmL3k3s0UR/LrzZoW/XCu+H5MuNwqZ3WM6j5v66wGewJE/CNbJ/A\nVt9EHU7WHk0vsbeBwrfCApEGsHUqa1AFy+hyM8BLxeGObElpfSeAOTwfyvri\nV+DE9S2DDt+Ozir1UynIZcLR5S1Gle7tkfiz3avfDSYKqLny2ua2QuhnI7jU\nLZi7CI8yCWZT2+OnI8JqQA8Bou+STxkOh/Titlysd7w5vRwHCd4jnYPS//Ts\ndxEKxav0ZctMDePbGkbGKElkByNJ/q6Lg5vKY3e5xilEc31R2o+ThWYYHUmm\nXpcZgUDzYpRmtTbRZJn7jACMpt3NOMmhoES/6InLd5mi7MbdSF28v6515Tys\nb1zWCo+wRtaLX38pa9Eq9ndvriGBEnTj+B1oNYRZxAHDzX2dSb7oUOAubbZF\nw+IispJxYORwjzo3vopwlTqUZDKUAgr+mCGs+6cW4P6P7qij6D71M27426Qo\nueP6R8dkhfQG9hK2KlVUXkdisPhTkPp4rVQAz7k+2DFjHbdMO0LSWayIc2wt\nWpVNmRKgtFitVPsQy/6RXehyI+lNSwylbfym6H4uPxjhCS6EY3wNlvgb4R+C\nHiw3lb5f315vWmtg3XMUWkL8ogCnwMKMK3PH0vljncBqbZlpabkYBnwOBHjm\nLJfa\r\n=5dVW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDmY5pAYYZBJKeDbzXS4IuCR7e7S3WgTIKU3ihWWTrJawIgW+P1aar933YaHX1uy0VNMh0KhmC5JVVY9hnluOXJbd0="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.5_1621415777579_0.43984770749333"},"_hasShrinkwrap":false},"9.11.6":{"name":"micro-kit-atlas","version":"9.11.6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.16","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.22.3","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.1","@types/lodash":"^4.14.167","@types/mocha":"^8.2.2","@types/node":"^14.14.37","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.11","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.22.0","@typescript-eslint/parser":"^4.22.0","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.24.0","mocha":"^8.3.2","nock":"^13.0.11","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^10.0.0","sinon-chai":"^3.6.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.2.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.885.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.1","ioredis":"^4.26.0","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"dc0c97d1c67cacabc676d3fed16c0950a8c0303f","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.6","_nodeVersion":"14.16.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-RRFUewqH/e/zpXq8ujjfJmirDSirItA9UMJqXIfK7iswAHNhpTJhdhvWduRyiIPNw3Iwnd5Gk803X8WlyfCInQ==","shasum":"ba537a04daed436a9ac728cec9b20d94b715f14c","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.6.tgz","fileCount":189,"unpackedSize":1364454,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgrg2ACRA9TVsSAnZWagAAffAQAIC+ZgO6FGwNBd8tUJvK\n3BamI4Q9GZf2Ta9fzsqOYmV9JDqO9Zdy9WjqARvri6LaI9f/ff/2D9X4pHFk\nZ97ERZqWPaclfHIA06iNG9XPLG08cfP5sDDWpYaUO83FmsKUvqVwZWWQmUXH\n9BAYfV194AoXUfnGXCMgOGNI72aI/qQp74CdcQwcctUIBKIN8sLiePoGO2bf\nuFHjJg7QBhFJwESoOgEvqb7IoeSVXLMUBZbjDkfRSYv1Vk06UMvVskHaVHuW\n6/5YwZVgTlVugjgTW1O3lQScOCqv+8kU7IzawTd5mVgEv6Ht13i4oydRkoKM\nYt5Ao4koX/94GLD8yBB+FBlaVbIW7Cc7fiUDQuoDkHb1Ru76RzyaY5M24Adk\neDV5diQ9AdAsiHvYkogGRri/NaLOBr/yiavIYWHmrBWqdHtQrnlt/AdB9wLb\nZI5UNu79Iz489uDAlTnSC2STT8+VC/xwGhAZ4rgM54mQEi2XwhEV9DNTnq1y\nv9h9n3RsYHMVCC1X7DFgXxAe1BC0pvUMLOd/9CvJIV0vqLexVPU5gDm9ZN1m\n6OlytRa6z1zue892oKrKGu+s8lMIsRs4xgdQr3xgs4nZ88kBs8eEt6iyOjY+\naE68275gqk24hJqyriY76ajC2twBG6JCqBSKqbw1wTCqPWEH1AHyikuvOLEu\n+lpK\r\n=BLlq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFLm31R+FfqVvUviB1OpOeHBo7Gc7h2gVd4mYs4ICYw8AiEAylllfeOuZJWhWr2W0BegUhpgeOn3994I6oUXVnGPV8c="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.6_1622019455514_0.9013495925484036"},"_hasShrinkwrap":false},"9.12.0-alpha-3":{"name":"micro-kit-atlas","version":"9.12.0-alpha-3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.1.1","@types/chai":"^4.2.16","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.22.3","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.1","@types/lodash":"^4.14.167","@types/mocha":"^8.2.2","@types/node":"^14.14.37","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.11","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.22.0","@typescript-eslint/parser":"^4.22.0","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.24.0","mocha":"^8.3.2","nock":"^13.0.11","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^10.0.0","sinon-chai":"^3.6.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.2.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.885.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.34.0","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.1","ioredis":"^4.26.0","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"0b499464bbbfd971d748f2c1e3cfd6c0b0fc075d","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.12.0-alpha-3","_nodeVersion":"16.3.0","_npmVersion":"7.15.1","dist":{"integrity":"sha512-n9rsWWgHVXZXRHCHx7B4fxvwI2vqIsjLVnETO8j9kPfjJ12hWdTVH2Ck9+ltok4IUcmKXpwnv8wDe6Nu86WNWw==","shasum":"ad75a1e19aa5caa320be74edcb93a39b19476158","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.12.0-alpha-3.tgz","fileCount":189,"unpackedSize":747035,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgv3jCCRA9TVsSAnZWagAAYxQP/0VdmBduW6OaEoJi0+Hq\nEAVb68Z1kUOijUMqr1FU4uzhd64AgtF+GZ27DFuwvO0ntM9UDOXlPvvsOy7B\np6EFXlLbKUy8dY6GszNAJFpGSGCB7YPOwsb6i1G1SakNxdaRnhSyOX0Hio6e\na++iTZEbe7wycV1qSMB+gIJMvOx6mqQjbtqnzXSX00bDVnw8skgVwhyTuLy6\nQMh0rOG0TPg/jsMy4sRSdbq0/mFMjk7Q6nHkhpwvcqSyscg18L3ls5Q/o/Bv\nKjjMSWDL1aASHs6UOJSjoiDer51KKYCRMYj+MkZcgz25zMGlvjaBMH36r3Rv\ncpBg9HrbIJbcif63XUtScxgo+VXMLhHip+ntvBfVcldtqFxkDOEhLxrCE3NW\nD4BsnPRvUgUveJwIyNKYwCpdwjPSz+sSA4GAdKQxcj2KOEiI8oxeWusGjlVb\noo/fNOJ51M11IrI7Luhcjh803+gmn5fu/X9PZ2HD+0h6uvf47N6amuoBtTV7\nX05G1LkcfX3D6C1UuLTuOxe+UTUzcIKT4B+DLi85yjK866fZ52HUcIvzIyNM\nu4RRXOOFYKQvpRK4cIcbojmaS2o4uOyDybPRiNz1Xk18bTW0Dw2w3/vHY0Ii\nb0zDjx8D6xT+33OXa1G32NHNImpdyHfx+qtKrOIvmoxliSA/OFLxbSMAkPCV\nzsjI\r\n=hk4P\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCSXzbzM0EF8S0pRWhhr6l9yKpLJBvR9oM9WH8HF/Zd+QIhALGNEdU55jvNuvCg6FRTRoAyAjAkPr82NfA/KzqgweJn"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.12.0-alpha-3_1623161026637_0.3793994792735511"},"_hasShrinkwrap":false},"9.11.7-alpha.1":{"name":"micro-kit-atlas","version":"9.11.7-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.16","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.22.3","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.1","@types/lodash":"^4.14.167","@types/mocha":"^8.2.2","@types/node":"^14.14.37","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.11","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.22.0","@typescript-eslint/parser":"^4.22.0","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.24.0","mocha":"^8.3.2","nock":"^13.0.11","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^10.0.0","sinon-chai":"^3.6.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.2.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.885.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.1","ioredis":"^4.26.0","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"e737e4d4bc7cd71977d28caa48d547c624417d67","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.7-alpha.1","_nodeVersion":"14.17.0","_npmVersion":"6.14.13","dist":{"integrity":"sha512-NZZysZAKcfeX6du63nn06TeP7D2hc5C82PV922BOzO5tLbqy5Y0sCgUA6QjzZRNh1bOwOnOvtqdFI1Q3PWGeKQ==","shasum":"fa150253063bf9c9b82c6dafc7b6377f1f2e25b1","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.7-alpha.1.tgz","fileCount":189,"unpackedSize":1367676,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgydTZCRA9TVsSAnZWagAAnKEP/Al6jrCU1pp65ZiCuSJ4\n6UkI4FyOVCDnOIxzAKhWcDTTaohTxsdnvgxdQA5J5YV9tmGaRVgDotAx9Fen\nZtRcnSYXe0Syi1V4T82chZRqR7/9TZMDreJ31IdX1+pPmkMBCD83E+uaCUzD\nLymKBzKSHkrkbXMOCeLwBDii01jaHe4fqONDB/YwGjzzzmqr4lPRc6XApLSt\no8NSNl6O1M+lLyl7FP4qqJSeoYZActOiC8gSlYQ/SeB79g+07lEdjloS1JBK\nJQniy/NNrGVo9SB1zVWLrO2Sevyereeo2sZFXf1y2XssFljkB/1qDppn/ioz\nvI+KJ+LXOpX1fal1qQkBAHQVXXrseh+lI+eTjyxv9dfAQpZKQAqSmlrc46Ed\nbebmhYWBDWSM8ZyiNcE94DezTakRomO7bKr7Zq88GOUrEvtakRWVc9kgvDvk\nHRGCVVw5aryCaC50TLk2TeRDQ0yhrLsIIiPHiiOO+5e/ExKVV+zunwVJe/hU\nzRRwaju+9aEiGfHT0ww6BA+rVFKfPLWLlBrp8doG8PX1hkKgcjCvPMKtc1J9\nxOzN9wqVRCh6q1lk9UUsznkRnkO2ttmNssBmm/oMVAWbojTfSqaM19zClEEQ\nUWKjlxhvFNT8G5xaY9R699xfrVDU5+yPmePI1ujRkzA80MEtE5Srr8kjSmcf\nWxmj\r\n=hIuq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFC3MudrOeQtMYkGKFRikcpj06KHX4dz8NFQ560ZnlSGAiBi25iftHkav+wWmCAuLUBgpfOpQ16lvTyc+1jSwDtHeQ=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.7-alpha.1_1623839961451_0.06078934835440619"},"_hasShrinkwrap":false},"9.11.7":{"name":"micro-kit-atlas","version":"9.11.7","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.16","@types/chai-as-promised":"^7.1.3","@types/dotenv":"^8.2.0","@types/express":"^4.17.11","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.22.3","@types/js-yaml":"^4.0.0","@types/jsonwebtoken":"^8.5.1","@types/lodash":"^4.14.167","@types/mocha":"^8.2.2","@types/node":"^14.14.37","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^9.0.11","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.3","@typescript-eslint/eslint-plugin":"^4.22.0","@typescript-eslint/parser":"^4.22.0","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.24.0","mocha":"^8.3.2","nock":"^13.0.11","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^10.0.0","sinon-chai":"^3.6.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^9.1.1","typescript":"^4.2.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.885.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"~0.31.4","decamelize":"^5.0.0","dotenv":"^8.2.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.1","ioredis":"^4.26.0","js-yaml":"^4.0.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.0.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"b5db5ca936aab4618e203dc20e0ad46aa8eaaafc","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.7","_nodeVersion":"14.17.0","_npmVersion":"6.14.13","dist":{"integrity":"sha512-cr0szE3hIO463ihqtmlEI9K20fG1H1iHOImFx6KVrrCfaqKU2/UV5wVR4IQYSKy/hVe8pA/YwVLiTDt6gDWtOg==","shasum":"99ed49b6db47d06a574f7283c52c078e6e8d74bd","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.7.tgz","fileCount":189,"unpackedSize":1367668,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgzHm1CRA9TVsSAnZWagAAa/4P/0Ll25vr24uZRYIe20WL\n8vGj8YD2eLPJk+bQzSeH0cw4/Bj4q6KUxoSyM9rOEOPkAJkkVWV+oGb75q+7\n+NPIxVjNZ5454gIvWn8zsKh9NI/O/K/dNcI93v+pIWzfMAI08C6fUG93GqB9\nDLf3oIkCtwgkq5ALMeoUbTbvd4mDIoaxoJIpoteC5LEZRsdaKHVb5B0DHtoX\nXvLnCP+9GaKOmXpJ8DKR6QER/HUYpdtbfumz1hnqshvmdE+O9a5301GfoaIy\nRAyrzt0Z7OE6Ydi5KjfUgQom8fFm9vHpUNdgPITj6DgWxf5dy+soWERE1qEe\nCqFGAKf0kssQSHEsCpKnt1z/myFiI/R/cK3DfVr6+2O7Z9SPkwHkAY3hXvyy\nSi3VZYg19zcQhVZZaAyv9AhZAy8v9IUyEJKBhALQNEMXIA+iq+EBrqI9gS0+\nMqRqZY2j5N+VoRLH1NVxHpXzDj0mQ9oXWshf/tPGK4UO//HIETqJ6wOR4zUa\nmlp9UXKqualdx6QX5TAyeQfSBo5406ywpnt0m6LdGahsyl/W8jIVBO77K4hB\ngIWIbFiwPxqL6D+fytor8wUAtGBFXqSNLhBkb2eMI4GcvP3XFy15xindu3aA\nfTSglbo2XDSQ7IYY+JHBVsUw4ra+xJ3v1TwO5zWB6XroHwJvKFGRflVbxz0k\nNFCd\r\n=esxe\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDsl0hHbcB0MSULsVbvU+s4PGj1fBf3zQIMoNpjUI+4XAIhAO4etyTu5hkzUGEtczp3SU392oq29/BIn+0mrjtESrxT"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.7_1624013236703_0.3756083198844986"},"_hasShrinkwrap":false},"9.11.8":{"name":"micro-kit-atlas","version":"9.11.8","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"011a2f70cf362669bca9695a1b8a2ff3a714b7db","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.8","_nodeVersion":"14.17.0","_npmVersion":"6.14.13","dist":{"integrity":"sha512-vOGC481CCdxnPuKWLA9gS4oHKpRzBq7ymQmr8iAbXZQ0j7jTLmMTmzqLEkjpjoLFcC/Dm4gnzZwypxT9qQaqCA==","shasum":"0722cf455ce59f5d4cac9f3318f204aaf4a0b2d6","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.8.tgz","fileCount":189,"unpackedSize":759099,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg3CtfCRA9TVsSAnZWagAAiDoQAIWpDqpUZWQ8MmRQ8t6n\n2npUR5h0+a9HgF3cuZXCu4myT1VmCPErZ+aALgsHGdxehkLaMgIrCrMBB4IS\n2LvHzBTH4SjKGuBteH+Q3BLAOKkWabrPdBI+fuiZW/PKp20oXS6RabgP/qll\nF1gDQnwNFEafy1jLW7lT6d+75oNYnQdu9LqBTcvLrHoQcgiyBRXkr+pszX1m\nqA2W9W+/PCaOikYhghqSLABNNlrpJ7NZzmTm8w3xREPtCuc6L89ohODOwwjs\nQRKN6nOiUN6IY0GRN6bhwZT4x4ZMDXg3agGhJU6L63YSC2gahaAb/xoBq/U4\nLfbkWwrAF6rISVG2OBUEDcTM5Ps3ubnYOMh7dV4Y/uV/JIq49XlIWL6IKoQY\nS88lIAp7gfwDR2v+yscf835WnXqQPvfsEXqfSxdgUiPWWWVx9jvAWfUvjvAB\novnmhglPK8dydOFQLH/UPvJsKJsqLJyzsy6AOEQDRk3xV9VRHetqt5hwsw7O\nd8jPyuoMhl2a9IrL41kcQWMNz0SFxUoo0SAZPb2PliObehIkcuDSx624BYmV\nV3vmY2XUkdhHxWVPnoh7aGapF1svOVM9lG5t0PGHwwBLdw6HRWSsby7DgpLF\neG04qFWr7juh6GTP/6KYL3P9hIRGhKDmSqr42WcVikxU0/SbRWaLeuE3I0Gu\n1m9j\r\n=RruG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHHBkMr+pp9GsoHtRzCrifoaCpjBBCclYjmXQJzMfmyZAiAJg6bXQzWHiZkAoOsgztOjJjQ4IEwry6es+DECabpUjw=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.8_1625041759181_0.23168575465501062"},"_hasShrinkwrap":false},"9.11.9-alpha.1":{"name":"micro-kit-atlas","version":"9.11.9-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"3770e84649b583cd77063522a0946e71bea1209d","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.9-alpha.1","_nodeVersion":"14.17.1","_npmVersion":"6.14.13","dist":{"integrity":"sha512-Z959rSvcVfPsuAAVhZ3NyUt26qV/yiEK770lnmELSQajKxYFqqSWwt6PzBNrxE14qvHK/H6NO6ouBpGKfvV9tw==","shasum":"d1d1e124110e55d40af154cf7cabafdae0e9ac3f","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.9-alpha.1.tgz","fileCount":189,"unpackedSize":759185,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg6BFNCRA9TVsSAnZWagAAKrQP/jk4ut1iQRshAUTcyvnU\ntzJW+MPnn3ni1BmasD/FhiH8+x9t4z+s8lO/pZbc90U49fFYnGeO7IMidiJ4\nCZqEIGf0uSQxDvODWK47HZTr9cOTzY8KO/J/BtYvN1rzTaieT7GmEHiXTa3v\n8ITo/uhjQaZ2A3fVfC4evgRdM/Rvd/WfakrGuA+xYANhEHZJeOzsTXeLsfB7\npwlEIBai0ZqWkMe+NmZzXH51JQa1SJa2sZDmrG2Dg7FxY+Fl9LDvfNDEl1oK\nSnCHRdbFAdG1DndNVtXL28u4XW7tPdsevbizvYleCrJL03ZQ7oZ6KXgGi4B5\n/hqtQqWdbb2x/USN8CJ44ZalUhIBVKPAtW3awkcBEbphPHOjeWtxO9FhPDgk\nC66mu25OqeIYO/i7yvIz6zPeGKF8l5toHgA3Fs2GCqrd0ZclkI/dPa9JoRwu\nC90xFh8UQfPekIaoJZLLjF919KVN7vGJLQWLemIMYj7LfH+mIdF2V26dvgjZ\nD3KSNT0R+iYQybnNNgRE7LqIdK+mbUH/TLXtpqt0bTAUBWF8SzaMrnuWNqny\nGxyt9fEmjY04F77s1FZxJvsI3b8K9KZU8CD8XJYHPksHPricXyyxVvzCtz6Y\nwzGibNifuFtmOI0KUaRb+OArISDp+XdYptTuIiZJzoBRVO6YArcx29SCNpaR\nrlvp\r\n=8zWg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCNeHWHu+wk6P7QMRkqLUNZPccN4iYVTWk2D/P8cVxqJwIgOb2lK+48UnKwGpuriFVkahj8TNRhAhXm7jJw5XdYokQ="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.9-alpha.1_1625821517425_0.7259980764255105"},"_hasShrinkwrap":false},"9.11.9-alpha.2":{"name":"micro-kit-atlas","version":"9.11.9-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"0e8958a1d2105aa0b798d64d076810c3a0a290bb","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.9-alpha.2","_nodeVersion":"14.17.1","_npmVersion":"6.14.13","dist":{"integrity":"sha512-2X6eoDlkV++b+3i0kh+duNQoKTPBqrBNczpdjhwvr/g7gzpxCh48xK7zJjenLsMEfcRxGqK9BukfYcD+5i/kkQ==","shasum":"b3f10b6d5ef889e01eae80a65b6c34a3662d528c","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.9-alpha.2.tgz","fileCount":189,"unpackedSize":756887,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg6DrVCRA9TVsSAnZWagAA+EAQAJmCjDUmpshKq0gN+bMe\nKAXOAzxWqurQIQiIpN7DN4rpgqXBEY2nqRHqXWiGr7ZAOno1a+t0DzE8osFl\nq/jW70Hs4bZGxK3zu7atRJmGtt1L1I8KT1zbA8bM1Q3/umnCGmd4JDn954r7\nJws+nAZK/b4DTnUlH43ULIl80BwTmlKX5+W+kXfJmA1SzpJwH1OVtCMMAvKr\n75F4TZB182o7ReMeWD2fuArnklE4ujAhp5Qca5MdeJKqh0RPiZxnGXLGGgI+\naWIei8//+tf35whuUK0xa1bHK1c4UZVYcdJCZhU+4+n7QxLfKlbtQlV4o2at\nbbEl1gd5GG3FqqMt/KWlo8Vwgcyyr7RRYhd1djlca7fPl2CwAD3aq9VK+r/q\nffItRvjofk31DqqSpcqbOU2ywbFuhh8dusw0D5XtHh/OtfFbkQtDWmpVgOPg\nBgH6xdKhN5rOB2ufev2jHTFcoAM15c6IevmAQQliuoTr0e3rQZsvsdI6+9kg\n4JsjuZ59fJHLW5P+AP9OckWi/t9UMjkTfpuS1lErPU83qrAspwpbi8xk6ymS\nBAKm9ComNMSW729BkDZdj93e3DCm8VQgcvYJ5JONKR2I9q29JjMkXN9wkWmr\nxjkeDDH1GmXtFmhPDgQolXm/zIXzbbU7NkyNdc4MaSIlu2A/guTYyAMPoabo\n6U9x\r\n=i/Oh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEuuevgEwCt7uvTP3ZPadgBvnDkC/X9cuwiR5gd0OtvCAiEA/zhRQ2WC6p7yL0H0LOhUtjO/5GvDLIqbORj8MwMnjhE="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.9-alpha.2_1625832149055_0.7369966643421255"},"_hasShrinkwrap":false},"9.11.9":{"name":"micro-kit-atlas","version":"9.11.9","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"43bbcefb4ac57ccab74dc76d1a612f47998957e5","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.9","_nodeVersion":"14.17.1","_npmVersion":"6.14.13","dist":{"integrity":"sha512-mi277PS5cH6+n+hsGE8K04sDdT38Z99pBqodVNRPEU+ZdfgknL8zFhzxV351W8INUmTRE9LksuVUQrj46WVRXg==","shasum":"2dcf7d3175e7a555c9c5cea06ac0c11c69a552c9","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.9.tgz","fileCount":189,"unpackedSize":756879,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg7APwCRA9TVsSAnZWagAAPqQP/i4lp2lnM/+Rhg0B/0ai\neaR+YJdXubtbZE9jWNGzYeN82c2Fc+h/G/O8KzrqaIHk9DjlF7vb51cNyPgd\nIJlsOycYMGalTp9bFm/KBJ4Zb4tW8//Ywy8kHJmaLcxKig7DK/6LWRHBDren\nLOS0v2W5mN3IovriUbRfV5h8maZWSdJ1aGx+xBFVdKJzy4z7Dpcih+OQIYP1\nCx2FccWHh4Pj4jWjKlONaZ1va7JBJj5S/WWkaxDb0hzQsVtbXQZeFJc9+C42\neDKApd65uATfnk6RNly64b2VQC8RsO0Sd+0LK6eJDzsqC2tjTSKwEUmIkpmt\nYNpZeLGoXDSFfqFrWAJslNXqZpZaPyl+aU8cP43sRT/wpZ5NnH7YzKm0Wljv\n9AIExQ/juGYc+i4ABFm6PnvmmioNCHKv05QpfceMozPuLAcV8Mz/3vy8WA6I\nCmZ+DDqGsC5iAFUwGehjUE9C6gfFFrDHeVnXu79JG6wjf+wBGi0sKN5Yi91h\n7yNe5Ds0wlTRUgV/Ou8Bkp2A8ikPoPx9rua5MPMN2iaxtslyzaRrLtoCvsZj\niGXtIhqRedG3lTGU426+zxVrZWtV84MVbCcfPHcMsCGuQpzPKPH7civWdOOK\ntON+v7au9X/ynCaU7qpZ05C+9l/w1P41lXMTuh9pYUccUfIg4fJBnHYrc20L\nt398\r\n=atDz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFkNpEpbumETLTxGbPA5gWpeVZEnpQdot7BFeoVpb1tZAiAexMppjg59DfNoB8n1yoAWLEV6o2tUjm4ays9ARrHQsg=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.9_1626080239995_0.9819999806738358"},"_hasShrinkwrap":false},"8.2.0-alpha-1":{"name":"micro-kit-atlas","version":"8.2.0-alpha-1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --require ts-node/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --require ts-node/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"^5.2.7","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"^5.0.38","@types/express":"^4.17.13","@types/http-aws-es":"^6.0.1","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^14.17.8","@types/sequelize":"^4.28.10","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","dirty-chai":"^2.0.1","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^6.2.3","nyc":"^14.1.1","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"^7.5.0","sinon-chai":"^3.7.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^5.0.1","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.5.2","aws-sdk":"^2.960.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^1.1.1","decamelize":"^1.2.0","dotenv":"^10.0.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.5.0","http-aws-es":"^6.0.0","ioredis":"^4.27.7","lodash":"^4.17.21","micro-kit-aws-queue":"~3.2.0","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^8.1.0","winston":"^3.3.3","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"a74999832b9ad2cf8f27393cae70ba3d9a2df79a","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize, setKeepAliveTimeout } from 'micro-kit-atlas'\n    \n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n    \n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initService()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n    \n#### TODO? \nDescribe init(options) and finalize(app)?\n    \n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Support.\n  - Ajv validation (only for HTTP request parameters).\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n    \nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `host`\n_string_ _optional_\n\n**To be removed.**\n\n#### `serviceName`\n _string_ _optional_\n \n **To be removed.**\n\n#### `service_root_uri`\n_string_ _optional_\n\nThe URI segment that identifies the service, after the versioning and before route part.\n\n`/v1/service_root_uri/route`\n\nIf this parameter is not provided the routes will have empty segment.\n\n`/v1//route`\n\n#### `namespace`\n_string_ _optional_\n\n **To be removed.**\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted. \n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n    \nRouting\n------\nFor apps using Atlas, routing must be initialized between the `atlas.init(options)` and `atlas.finalize(app)`\n \n#### Basic use\nroutes.ts\n```typescript\n    import { router, Router } from 'micro-kit-atlas'\n    \n    export function init () {\n      router.exposed.GET('status', 1, async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n```\napp.ts\n```typescript    \n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    import * as routes from './routes'\n    \n    const options: Lib.Config = {\n      name: 'check_status',\n      service_root_uri: 'check_status',\n    }\n    \n    export async function initApp (): Promise<any> {\n      try {\n        const app = await init(options)\n        routes.init()\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initApp()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n    \nTo see the example in browser open `http://localhost:8080/v1/check_status/status`\n\n\nThe Router in Atlas has three interfaces, _ExposedRouter_, _ProtectedRouter_ and _InternalRouter_, available as `exposed`, `tokenProtected`, and `internal`. Both of them have the same static properties but with different signatures, the exposed router requires a version input while the internal defaults the version to `/internal/`. \n\n#### Exposed\n\n    static GET(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The express `request` is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\n#### Protected\n\n    static GET(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The ProtectedRequest (express `request`, extended with `req.tokenData`) is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\nProtected routes have a middleware check that the request has hit the API with req.tokenData attached. \nThe tokenData must contain the fields `globalid`, `uuid`, `client_id`, `scopes` and `grant_type` to make it past the middleware. A request without tokenData or without these fields will be met with a 401 Unauthorised response.\nAs a result, the controller gets a ProtectedRequest instead of a Request, so you can work with req.tokenData without worry.\n\nExample controller\n```typescript\nrouter.tokenProtected.GET('identities/me/is-dave', 1, exampleProtectedRequest, { schemaConfig: { params: '/IdentityUpdateGetParameters', validator: support.schema.validator }, })\n```\n```typescript\n\nexport async function exampleProtectedRequest (req: Router.ProtectedRequest, res: Router.ResponseHandler): Promise<boolean> {\n  const daves_uuid = '86d7e731-da23-4e2f-951e-81a04665f002'\n  const gid_uuid_in_token = req.tokenData.uuid // Router.ProtectedRequest says req has tokenData and tokenData is of type TokenData\n  return gid_uuid_in_token === daves_uuid\n}\n```\n\n#### Internal\n\n    static GET(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n\nExample:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\nExample with redirect response:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request, h: Router.ResponseHandler): Promise<Router.CustomResponse> => {\n        return h.redirect('https://globalid.net');\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\n\nSupport\n------\n#### Schema Validator for Routing\n\nAtlas offers json schema validation on the router with [Ajv](https://github.com/epoberezkin/ajv). \nHere is example how to implement uuid validation for a url parameter. First lets create the Ajv schema object:\n```typescript\n    // schemas.ts        \n    export const byUUID = {\n      $id: '/byUUID',\n      properties: {\n        uuid: {\n          $ref: '/UUID'\n        }\n      },\n      required: [\n        'uuid'\n      ]\n    }\n```   \nNext in app.ts we import all the defined schemas, in this case just `byUUID` and we load them to the Ajv validator at service startup:\n```typescript\n    import * as schemas from './schemas'\n    \n    // load all schemas\n    export const registerSchemas = async () => {\n      support.schema.addSchemasRecursive(schemas)\n    }\n    \n    ...\n    await registerSchemas()\n    await finalize(app)\n    ...\n````\nAfter that, on the router any route can validate uuid values that are on `req.body`, `req.query` or `req.param`. Here is route that expects uuid as url param:\n```typescript\n    import { router, Router, support } from 'micro-kit-atlas'\n    \n    const uuidSchemaConfig: Router.RequestValidation = {\n      validator: support.schema.validator, // Pass the Ajv validator\n      params: '/byUUID' // The $id of the schema\n    }\n    \n    export function init () {\n      router.exposed.GET('status/:uuid', 1, async (req: Router.Request) => {\n        return {id: req.params.uuid}\n      }, uuidSchemaConfig)\n    }\n    \n    export default {\n      init\n    }\n```\nCalling the route with invalid uuid will return error:\n    \n    http://localhost:8080/v1/check_status/get_uuid/123\n    {\"fields\":{\"missing\":[],\"uuid\":\"should match format \\\"uuid\\\"\"},\"error_id\":\"1adf7eae-c488-47b3-8c91-fb5942c60444\"}\n\nTo run the example:\n\n    cd examples\n    npm install\n    npm run support:schema\n    open http://localhost:8080/v1/check_status/get_uuid/with_bad_uuid\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client \nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n \n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html). \n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@8.2.0-alpha-1","_nodeVersion":"14.17.3","_npmVersion":"6.14.13","dist":{"integrity":"sha512-iOBITWFYQ4AlkFAWKUN2bQHCwOjAbYr9L2bNDoDT7/LTaZeusBdv7WTHEsZLlfDWCv1XfRGAtTVI0+Qip6F+qA==","shasum":"e23fef7a99f29e2eac657b8522e8167b77966d67","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.2.0-alpha-1.tgz","fileCount":61,"unpackedSize":142156,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhC9NyCRA9TVsSAnZWagAAnRgP/0+yT3DSzuUjYfSdSbUJ\nLeulc9ejpVDge7bE0cVIdEPorV2w6Cb0Gk5eAjMvDZ8uHyAsqUanllWgMcjf\nyl/+2pFvu3tTsiVycudPnei3hH4rrqVx9wxWiF4VXphbpMESVF/mGe8Q5jzP\nGDGfUds3tW1/0bP4ZVcEfUfGrbWQD9V/cswy0L1Qm3rw52aM2vnVvd3NR7iu\nvfjZDjm58PPTRITOCtwWyZoykLkLVH4lhNxCIE1Y3uVEBQAufXwHLOvQyY5b\nEpb2/pvfLN0T8C9XrDmViN6X19KSh2V/g14Ys0ikRflquj2PRi3Uh2Dtl7wn\nungMmy+qliHsgH+oXX9YO9zcXy9mslMy/ZOauVs8v/RRibhdF8lg4UnnMfpw\n19JOpWyxINwvwCme0pyOL3ZNuLNoRFegyWELGJTKBlqF4jVsU9ET1rebeO2y\nXpW617cAgJDE2PjxM94nne0Ix8p0iiRmN/p0hEEXl/Ioz6EIFaE/N1fL14xI\nQIkgw1jvBLQK71gJUIIvtlP1BhJsOBZXni6wXziulu+eYVvKi3eAMuByni0z\ny8ZblzfXO6YnetwDc20aj4KsIzAdLkfhxw/g7f8uy4NtL7YCgHKjBf63ClfR\n3meGQ1DEmBI3GEpfw5RPSXHlh66ZJnTdGv93wSTp1Vp4YBcm71zhPm7q9liD\n2mKb\r\n=8TVg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDWL8bx0AiHuLS778JU1c7zP74KRTbpCGMKLKKO0ZNyFQIhAL8yl5V/QA3Y+1RxC/C6CERPw3+rCA4j4lB18qRcQ/Ix"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.2.0-alpha-1_1628164978596_0.15496063873633514"},"_hasShrinkwrap":false},"8.2.0-alpha-2":{"name":"micro-kit-atlas","version":"8.2.0-alpha-2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --require ts-node/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --require ts-node/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"^5.2.7","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"^5.0.38","@types/express":"^4.17.11","@types/http-aws-es":"^6.0.1","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^14.17.8","@types/sequelize":"^4.28.10","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","dirty-chai":"^2.0.1","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^6.2.3","nyc":"^14.1.1","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"^7.5.0","sinon-chai":"^3.7.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^5.0.1","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.5.2","aws-sdk":"^2.960.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^1.1.1","decamelize":"^1.2.0","dotenv":"^10.0.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.5.0","http-aws-es":"^6.0.0","ioredis":"^4.27.7","lodash":"^4.17.21","micro-kit-aws-queue":"~3.2.0","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^8.1.0","winston":"^3.3.3","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"15cf9c6c65e773167b0408758b28891f11f0353c","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize, setKeepAliveTimeout } from 'micro-kit-atlas'\n    \n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n    \n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initService()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n    \n#### TODO? \nDescribe init(options) and finalize(app)?\n    \n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Support.\n  - Ajv validation (only for HTTP request parameters).\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n    \nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `host`\n_string_ _optional_\n\n**To be removed.**\n\n#### `serviceName`\n _string_ _optional_\n \n **To be removed.**\n\n#### `service_root_uri`\n_string_ _optional_\n\nThe URI segment that identifies the service, after the versioning and before route part.\n\n`/v1/service_root_uri/route`\n\nIf this parameter is not provided the routes will have empty segment.\n\n`/v1//route`\n\n#### `namespace`\n_string_ _optional_\n\n **To be removed.**\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted. \n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n    \nRouting\n------\nFor apps using Atlas, routing must be initialized between the `atlas.init(options)` and `atlas.finalize(app)`\n \n#### Basic use\nroutes.ts\n```typescript\n    import { router, Router } from 'micro-kit-atlas'\n    \n    export function init () {\n      router.exposed.GET('status', 1, async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n```\napp.ts\n```typescript    \n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    import * as routes from './routes'\n    \n    const options: Lib.Config = {\n      name: 'check_status',\n      service_root_uri: 'check_status',\n    }\n    \n    export async function initApp (): Promise<any> {\n      try {\n        const app = await init(options)\n        routes.init()\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initApp()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n    \nTo see the example in browser open `http://localhost:8080/v1/check_status/status`\n\n\nThe Router in Atlas has three interfaces, _ExposedRouter_, _ProtectedRouter_ and _InternalRouter_, available as `exposed`, `tokenProtected`, and `internal`. Both of them have the same static properties but with different signatures, the exposed router requires a version input while the internal defaults the version to `/internal/`. \n\n#### Exposed\n\n    static GET(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The express `request` is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\n#### Protected\n\n    static GET(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The ProtectedRequest (express `request`, extended with `req.tokenData`) is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\nProtected routes have a middleware check that the request has hit the API with req.tokenData attached. \nThe tokenData must contain the fields `globalid`, `uuid`, `client_id`, `scopes` and `grant_type` to make it past the middleware. A request without tokenData or without these fields will be met with a 401 Unauthorised response.\nAs a result, the controller gets a ProtectedRequest instead of a Request, so you can work with req.tokenData without worry.\n\nExample controller\n```typescript\nrouter.tokenProtected.GET('identities/me/is-dave', 1, exampleProtectedRequest, { schemaConfig: { params: '/IdentityUpdateGetParameters', validator: support.schema.validator }, })\n```\n```typescript\n\nexport async function exampleProtectedRequest (req: Router.ProtectedRequest, res: Router.ResponseHandler): Promise<boolean> {\n  const daves_uuid = '86d7e731-da23-4e2f-951e-81a04665f002'\n  const gid_uuid_in_token = req.tokenData.uuid // Router.ProtectedRequest says req has tokenData and tokenData is of type TokenData\n  return gid_uuid_in_token === daves_uuid\n}\n```\n\n#### Internal\n\n    static GET(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n\nExample:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\nExample with redirect response:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request, h: Router.ResponseHandler): Promise<Router.CustomResponse> => {\n        return h.redirect('https://globalid.net');\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\n\nSupport\n------\n#### Schema Validator for Routing\n\nAtlas offers json schema validation on the router with [Ajv](https://github.com/epoberezkin/ajv). \nHere is example how to implement uuid validation for a url parameter. First lets create the Ajv schema object:\n```typescript\n    // schemas.ts        \n    export const byUUID = {\n      $id: '/byUUID',\n      properties: {\n        uuid: {\n          $ref: '/UUID'\n        }\n      },\n      required: [\n        'uuid'\n      ]\n    }\n```   \nNext in app.ts we import all the defined schemas, in this case just `byUUID` and we load them to the Ajv validator at service startup:\n```typescript\n    import * as schemas from './schemas'\n    \n    // load all schemas\n    export const registerSchemas = async () => {\n      support.schema.addSchemasRecursive(schemas)\n    }\n    \n    ...\n    await registerSchemas()\n    await finalize(app)\n    ...\n````\nAfter that, on the router any route can validate uuid values that are on `req.body`, `req.query` or `req.param`. Here is route that expects uuid as url param:\n```typescript\n    import { router, Router, support } from 'micro-kit-atlas'\n    \n    const uuidSchemaConfig: Router.RequestValidation = {\n      validator: support.schema.validator, // Pass the Ajv validator\n      params: '/byUUID' // The $id of the schema\n    }\n    \n    export function init () {\n      router.exposed.GET('status/:uuid', 1, async (req: Router.Request) => {\n        return {id: req.params.uuid}\n      }, uuidSchemaConfig)\n    }\n    \n    export default {\n      init\n    }\n```\nCalling the route with invalid uuid will return error:\n    \n    http://localhost:8080/v1/check_status/get_uuid/123\n    {\"fields\":{\"missing\":[],\"uuid\":\"should match format \\\"uuid\\\"\"},\"error_id\":\"1adf7eae-c488-47b3-8c91-fb5942c60444\"}\n\nTo run the example:\n\n    cd examples\n    npm install\n    npm run support:schema\n    open http://localhost:8080/v1/check_status/get_uuid/with_bad_uuid\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client \nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n \n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html). \n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@8.2.0-alpha-2","_nodeVersion":"14.17.3","_npmVersion":"6.14.13","dist":{"integrity":"sha512-KcEoLXMgWiqdX1hahZso4y3Q+FjFfJOM4qEUglEloia1aLrhUTpMsFaPmjm7tOW7qKev4BnbbXKdBo7HRkpVvQ==","shasum":"7d2ed3f06d6da95db2514b986c18879923a9fcc6","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.2.0-alpha-2.tgz","fileCount":61,"unpackedSize":142156,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhC+eMCRA9TVsSAnZWagAAbjAP/3hOluvxrWw9FE33B+Oi\nncZ+Ty2y92ERg9DFqoJqlE1GpZQdvWXj5jfxIBMaTiWXk+Wnmgvb/b0oINTj\nlwbwWwhbKdOlHbm8Hstp1iMYwdF2YbL8t8z+6/VS/pEmXabmG71lw7lXAT9u\n01K75N+jriJtF2ceXqVxm1PMEgdXVBs7vjocvMG6ZgIQCxVWYHxbbTfpA/NC\ni5ynd335jEIsDtHhIn8ZdprYvvbxMw4bpKNy12EiyvAppaExStuKU7cocuDg\nhjvtYeR+uyt7GuLB+YvVIH4j+YFzJcJzniNt9gnY00+4gNR2wWzt6aB8a4r/\nM51SN+M4mSCikBaeiTwlY8tZadOmFNcgw9me98Nwj/QP3gqnyn+qtqF8awMR\ntMovMtrYqcZdVx1SLI5YyH+ENrFCH+fcDeRaQvm8DVqDZdbe6khnNVbk/+q6\nBWqwEwXna3qvBzq5pvrpuoseGdRRA52ANdLZJ8n92L22d5NsyB6BfKKyXVZ5\nvl/oD5/iUqeik20+yVK8vm0E7/XDc+HIOQPSXt2FM0PMR+MlO5bBNbK1UiNn\nssrtBGaRgPDbFnLsdGvQCkO4KIO0PbBA/uLDxt8g0Wh63zXsv6q8Ur15EewJ\nhor9fIhZMJaLCpHRS5ZfLIgjdFD6fy2PQ5q+W0398RyUaOar1FPRXqVBOx5z\njG0b\r\n=DCPn\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDy/oTXLt4Mj/RTAw9wGpIb/bqkj+vXCyprX/aDJ23x2wIhAKHDIgZMWRbfxJuvY4eOXRlloQwyn3mLhefxMpAUcGFC"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.2.0-alpha-2_1628170123994_0.17141945675653503"},"_hasShrinkwrap":false},"8.2.0-alpha-3":{"name":"micro-kit-atlas","version":"8.2.0-alpha-3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --require ts-node/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --require ts-node/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"^5.2.7","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"^5.0.38","@types/express":"4.17.11","@types/http-aws-es":"^6.0.1","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^14.17.8","@types/sequelize":"^4.28.10","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","dirty-chai":"^2.0.1","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^6.2.3","nyc":"^14.1.1","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"^7.5.0","sinon-chai":"^3.7.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^5.0.1","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.5.2","aws-sdk":"^2.960.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^1.1.1","decamelize":"^1.2.0","dotenv":"^10.0.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.5.0","http-aws-es":"^6.0.0","ioredis":"^4.27.7","lodash":"^4.17.21","micro-kit-aws-queue":"~3.2.0","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^8.1.0","winston":"^3.3.3","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"dc6f744e0a39654a4cedbdabd3b8da7e10e3ccda","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize, setKeepAliveTimeout } from 'micro-kit-atlas'\n    \n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n    \n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initService()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n    \n#### TODO? \nDescribe init(options) and finalize(app)?\n    \n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Support.\n  - Ajv validation (only for HTTP request parameters).\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n    \nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `host`\n_string_ _optional_\n\n**To be removed.**\n\n#### `serviceName`\n _string_ _optional_\n \n **To be removed.**\n\n#### `service_root_uri`\n_string_ _optional_\n\nThe URI segment that identifies the service, after the versioning and before route part.\n\n`/v1/service_root_uri/route`\n\nIf this parameter is not provided the routes will have empty segment.\n\n`/v1//route`\n\n#### `namespace`\n_string_ _optional_\n\n **To be removed.**\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted. \n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n    \nRouting\n------\nFor apps using Atlas, routing must be initialized between the `atlas.init(options)` and `atlas.finalize(app)`\n \n#### Basic use\nroutes.ts\n```typescript\n    import { router, Router } from 'micro-kit-atlas'\n    \n    export function init () {\n      router.exposed.GET('status', 1, async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n```\napp.ts\n```typescript    \n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    import * as routes from './routes'\n    \n    const options: Lib.Config = {\n      name: 'check_status',\n      service_root_uri: 'check_status',\n    }\n    \n    export async function initApp (): Promise<any> {\n      try {\n        const app = await init(options)\n        routes.init()\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initApp()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n    \nTo see the example in browser open `http://localhost:8080/v1/check_status/status`\n\n\nThe Router in Atlas has three interfaces, _ExposedRouter_, _ProtectedRouter_ and _InternalRouter_, available as `exposed`, `tokenProtected`, and `internal`. Both of them have the same static properties but with different signatures, the exposed router requires a version input while the internal defaults the version to `/internal/`. \n\n#### Exposed\n\n    static GET(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The express `request` is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\n#### Protected\n\n    static GET(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The ProtectedRequest (express `request`, extended with `req.tokenData`) is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\nProtected routes have a middleware check that the request has hit the API with req.tokenData attached. \nThe tokenData must contain the fields `globalid`, `uuid`, `client_id`, `scopes` and `grant_type` to make it past the middleware. A request without tokenData or without these fields will be met with a 401 Unauthorised response.\nAs a result, the controller gets a ProtectedRequest instead of a Request, so you can work with req.tokenData without worry.\n\nExample controller\n```typescript\nrouter.tokenProtected.GET('identities/me/is-dave', 1, exampleProtectedRequest, { schemaConfig: { params: '/IdentityUpdateGetParameters', validator: support.schema.validator }, })\n```\n```typescript\n\nexport async function exampleProtectedRequest (req: Router.ProtectedRequest, res: Router.ResponseHandler): Promise<boolean> {\n  const daves_uuid = '86d7e731-da23-4e2f-951e-81a04665f002'\n  const gid_uuid_in_token = req.tokenData.uuid // Router.ProtectedRequest says req has tokenData and tokenData is of type TokenData\n  return gid_uuid_in_token === daves_uuid\n}\n```\n\n#### Internal\n\n    static GET(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n\nExample:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\nExample with redirect response:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request, h: Router.ResponseHandler): Promise<Router.CustomResponse> => {\n        return h.redirect('https://globalid.net');\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\n\nSupport\n------\n#### Schema Validator for Routing\n\nAtlas offers json schema validation on the router with [Ajv](https://github.com/epoberezkin/ajv). \nHere is example how to implement uuid validation for a url parameter. First lets create the Ajv schema object:\n```typescript\n    // schemas.ts        \n    export const byUUID = {\n      $id: '/byUUID',\n      properties: {\n        uuid: {\n          $ref: '/UUID'\n        }\n      },\n      required: [\n        'uuid'\n      ]\n    }\n```   \nNext in app.ts we import all the defined schemas, in this case just `byUUID` and we load them to the Ajv validator at service startup:\n```typescript\n    import * as schemas from './schemas'\n    \n    // load all schemas\n    export const registerSchemas = async () => {\n      support.schema.addSchemasRecursive(schemas)\n    }\n    \n    ...\n    await registerSchemas()\n    await finalize(app)\n    ...\n````\nAfter that, on the router any route can validate uuid values that are on `req.body`, `req.query` or `req.param`. Here is route that expects uuid as url param:\n```typescript\n    import { router, Router, support } from 'micro-kit-atlas'\n    \n    const uuidSchemaConfig: Router.RequestValidation = {\n      validator: support.schema.validator, // Pass the Ajv validator\n      params: '/byUUID' // The $id of the schema\n    }\n    \n    export function init () {\n      router.exposed.GET('status/:uuid', 1, async (req: Router.Request) => {\n        return {id: req.params.uuid}\n      }, uuidSchemaConfig)\n    }\n    \n    export default {\n      init\n    }\n```\nCalling the route with invalid uuid will return error:\n    \n    http://localhost:8080/v1/check_status/get_uuid/123\n    {\"fields\":{\"missing\":[],\"uuid\":\"should match format \\\"uuid\\\"\"},\"error_id\":\"1adf7eae-c488-47b3-8c91-fb5942c60444\"}\n\nTo run the example:\n\n    cd examples\n    npm install\n    npm run support:schema\n    open http://localhost:8080/v1/check_status/get_uuid/with_bad_uuid\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client \nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n \n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html). \n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@8.2.0-alpha-3","_nodeVersion":"14.17.3","_npmVersion":"6.14.13","dist":{"integrity":"sha512-G5VKZYVFN/98bektflGJa6owoMFa3twmChVi8OttjNE6DuAVGvRSpajc2eAST6inQQ7XkcLSN1PWgnde123wtQ==","shasum":"8b0357ac6f8d5b4522cbcad6334bad9729f0571c","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.2.0-alpha-3.tgz","fileCount":61,"unpackedSize":142155,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhC/plCRA9TVsSAnZWagAAOTUP/0kqCEo+HmXB0wDXrOjI\nOLP3Q1zlDI3SEMlHtLdLiyIG4BD+gJGzQFdtYXQ/N44eBrFW337ATUrAv5nH\nEOQIctM5ZTYztoXYx3jCJd+NEiQGi/4wCwm8TJ9osxNr7ww+v64N0N21Yv7i\n3Th+Cf4TD90egeTYx3rgghHLQaE3RlzDIArhbs+P+IrGqBj0RmnbGABY6r4y\n65QDy4NS5nxPFFaVdtG9OJYvKev8m1JV0rwe+rESfTmsgxna3/H+DEZfZll9\npHvjiPpx66yPnCqz5RU7xW0+3X3Rh2Weky3wIHxK8uZlhpz1/h1Fy2sVFwwI\nxMpn8vFpLi4ZPKGVyVjQfqWgpD9w9fDorZy9P/E6t/Kn2Cb+mVpkXwSQTpH1\nL+mNEa43jM1dBAwBQXAVkYWloWjjhAGnkILktB2sBEk5YMJ3J6/glp2i0EyW\n/k/z8GKwIbatjRfZd0ekPYn6LvXRvY7086R8qR/Bs/CifSTm+bIKcUTRBUtq\n6K+UIsO64MU7VlDmm9s5fL2c+qGXwT48dmRx41sOV1PpjTqMdsNTm9BS5jX2\n7FUI3MGcVjb+SCKG78uVF5UbUh9xjg6j+S+vuNb9EXGM8dypwoLp3hCGItQN\nagLS69U3S1dMhye+RwIL04wfSzaVFej703d34FtnMCuu0jfzPl55hfI66YZ6\n9nUe\r\n=uVbF\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF9dH6RDWhcZCZDMvfzZ3oXOwC762PO/FOlnG+2gxR5sAiEAp0PZ+VpV/sfArfKrU1Ll8ZTSDyoXv7FaerTy0Z2oDUU="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.2.0-alpha-3_1628174948933_0.4448122561930463"},"_hasShrinkwrap":false},"8.2.0-alpha-4":{"name":"micro-kit-atlas","version":"8.2.0-alpha-4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --require ts-node/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --require ts-node/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"^5.2.7","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"^5.0.38","@types/express":"4.17.0","@types/express-serve-static-core":"4.16.7","@types/http-aws-es":"^6.0.1","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^14.17.8","@types/sequelize":"^4.28.10","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","dirty-chai":"^2.0.1","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^6.2.3","nyc":"^14.1.1","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"^7.5.0","sinon-chai":"^3.7.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^5.0.1","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.5.2","aws-sdk":"^2.960.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^1.1.1","decamelize":"^1.2.0","dotenv":"^10.0.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.5.0","http-aws-es":"^6.0.0","ioredis":"^4.27.7","lodash":"^4.17.21","micro-kit-aws-queue":"~3.2.0","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^8.1.0","winston":"^3.3.3","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"b9d371e2d124edc81625320b9c70c4a9e5e5034b","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize, setKeepAliveTimeout } from 'micro-kit-atlas'\n    \n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n    \n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initService()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n    \n#### TODO? \nDescribe init(options) and finalize(app)?\n    \n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Support.\n  - Ajv validation (only for HTTP request parameters).\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n    \nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `host`\n_string_ _optional_\n\n**To be removed.**\n\n#### `serviceName`\n _string_ _optional_\n \n **To be removed.**\n\n#### `service_root_uri`\n_string_ _optional_\n\nThe URI segment that identifies the service, after the versioning and before route part.\n\n`/v1/service_root_uri/route`\n\nIf this parameter is not provided the routes will have empty segment.\n\n`/v1//route`\n\n#### `namespace`\n_string_ _optional_\n\n **To be removed.**\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted. \n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n    \nRouting\n------\nFor apps using Atlas, routing must be initialized between the `atlas.init(options)` and `atlas.finalize(app)`\n \n#### Basic use\nroutes.ts\n```typescript\n    import { router, Router } from 'micro-kit-atlas'\n    \n    export function init () {\n      router.exposed.GET('status', 1, async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n```\napp.ts\n```typescript    \n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    import * as routes from './routes'\n    \n    const options: Lib.Config = {\n      name: 'check_status',\n      service_root_uri: 'check_status',\n    }\n    \n    export async function initApp (): Promise<any> {\n      try {\n        const app = await init(options)\n        routes.init()\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initApp()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n    \nTo see the example in browser open `http://localhost:8080/v1/check_status/status`\n\n\nThe Router in Atlas has three interfaces, _ExposedRouter_, _ProtectedRouter_ and _InternalRouter_, available as `exposed`, `tokenProtected`, and `internal`. Both of them have the same static properties but with different signatures, the exposed router requires a version input while the internal defaults the version to `/internal/`. \n\n#### Exposed\n\n    static GET(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The express `request` is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\n#### Protected\n\n    static GET(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The ProtectedRequest (express `request`, extended with `req.tokenData`) is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\nProtected routes have a middleware check that the request has hit the API with req.tokenData attached. \nThe tokenData must contain the fields `globalid`, `uuid`, `client_id`, `scopes` and `grant_type` to make it past the middleware. A request without tokenData or without these fields will be met with a 401 Unauthorised response.\nAs a result, the controller gets a ProtectedRequest instead of a Request, so you can work with req.tokenData without worry.\n\nExample controller\n```typescript\nrouter.tokenProtected.GET('identities/me/is-dave', 1, exampleProtectedRequest, { schemaConfig: { params: '/IdentityUpdateGetParameters', validator: support.schema.validator }, })\n```\n```typescript\n\nexport async function exampleProtectedRequest (req: Router.ProtectedRequest, res: Router.ResponseHandler): Promise<boolean> {\n  const daves_uuid = '86d7e731-da23-4e2f-951e-81a04665f002'\n  const gid_uuid_in_token = req.tokenData.uuid // Router.ProtectedRequest says req has tokenData and tokenData is of type TokenData\n  return gid_uuid_in_token === daves_uuid\n}\n```\n\n#### Internal\n\n    static GET(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n\nExample:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\nExample with redirect response:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request, h: Router.ResponseHandler): Promise<Router.CustomResponse> => {\n        return h.redirect('https://globalid.net');\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\n\nSupport\n------\n#### Schema Validator for Routing\n\nAtlas offers json schema validation on the router with [Ajv](https://github.com/epoberezkin/ajv). \nHere is example how to implement uuid validation for a url parameter. First lets create the Ajv schema object:\n```typescript\n    // schemas.ts        \n    export const byUUID = {\n      $id: '/byUUID',\n      properties: {\n        uuid: {\n          $ref: '/UUID'\n        }\n      },\n      required: [\n        'uuid'\n      ]\n    }\n```   \nNext in app.ts we import all the defined schemas, in this case just `byUUID` and we load them to the Ajv validator at service startup:\n```typescript\n    import * as schemas from './schemas'\n    \n    // load all schemas\n    export const registerSchemas = async () => {\n      support.schema.addSchemasRecursive(schemas)\n    }\n    \n    ...\n    await registerSchemas()\n    await finalize(app)\n    ...\n````\nAfter that, on the router any route can validate uuid values that are on `req.body`, `req.query` or `req.param`. Here is route that expects uuid as url param:\n```typescript\n    import { router, Router, support } from 'micro-kit-atlas'\n    \n    const uuidSchemaConfig: Router.RequestValidation = {\n      validator: support.schema.validator, // Pass the Ajv validator\n      params: '/byUUID' // The $id of the schema\n    }\n    \n    export function init () {\n      router.exposed.GET('status/:uuid', 1, async (req: Router.Request) => {\n        return {id: req.params.uuid}\n      }, uuidSchemaConfig)\n    }\n    \n    export default {\n      init\n    }\n```\nCalling the route with invalid uuid will return error:\n    \n    http://localhost:8080/v1/check_status/get_uuid/123\n    {\"fields\":{\"missing\":[],\"uuid\":\"should match format \\\"uuid\\\"\"},\"error_id\":\"1adf7eae-c488-47b3-8c91-fb5942c60444\"}\n\nTo run the example:\n\n    cd examples\n    npm install\n    npm run support:schema\n    open http://localhost:8080/v1/check_status/get_uuid/with_bad_uuid\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client \nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n \n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html). \n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@8.2.0-alpha-4","_nodeVersion":"14.17.3","_npmVersion":"6.14.13","dist":{"integrity":"sha512-7W5F8zozdhx+F3V3sgEYV+yd6Kt3d4JKAiCDV+JdSZWNBNcMVa+P+dYFCjA2mtFRKmw4E7nJS6qXIxYqYQwhXw==","shasum":"3b4cefef3ddd429ce08fe489ed390b53be3aedf5","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.2.0-alpha-4.tgz","fileCount":61,"unpackedSize":142204,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhDOxFCRA9TVsSAnZWagAAYTQP/0Doz0BroHbwW8Zsxna/\nc2X4jNd+dPzC2yDL6/55QKAtHp2BTNQYxcgopUo+agqHynpOf7XS88GocOea\nJLOC1txVc2Oaz4GEeBKEKmh/3xajbyht9Rte7Bhql0XKQ6w1ftx6a8wHZnux\n3nxzQNl+H+JnsCLyaw4qa2LIC/lmNnznwxVM9xnw3E6xhr3qdZQJtakdRwwQ\nNYf62sEFNEon6/QVJvOrQOJ+eOR2j5O2LYwkH2OEfT9QvTezszxOqiEXSIts\nAoUwNqVBMe17yM9AMEdeAHNGf1xhXbFiIDOmgFMw81QkHhHYjYCLZWdcz+1/\naaEE8ekt09WboX4dEAMKN9YgHO4ZNrm2B1YECO2VLqSSJTwa53RdJ+F6fYoU\nH033PDqsYsMkDKAjPyJGol1JjV+eguQR1XNE3mjmq/22YRXcSku20k7FLiFU\nGKV9AF0mgOHaBZtp83VujXOtpN9MUDEFTMKJlPbMlZr8n4cYel+HnGiaxxbN\nibyf0NY7iTccyqJpWFejilt/YJs63nNL8UIGcGjDCiuUbn+8fg4cY7Mztvog\nWKaCTVt8jTALirtgwWbo7buUtWaf7+0SuMFukBDCugW4aMnTqsoKcvceZzBs\nJRoZ1WK4ym7Zb7IYgtioJbjZXOXx75qsXmFOcxhmWonUG3p5HVdV6jVnADuw\nh3AK\r\n=3G56\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDoKp+C39Jwf0s76eCz87Rvi/IAjFDyrSu85uyyV3U1bQIhAO4juBcagHuumQiSmctrq5tJ0dZvvB157wpAkz9eYOjg"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.2.0-alpha-4_1628236869207_0.5036600605050152"},"_hasShrinkwrap":false},"8.2.0":{"name":"micro-kit-atlas","version":"8.2.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --require ts-node/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --require ts-node/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"^5.2.7","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"^5.0.38","@types/express":"4.17.0","@types/express-serve-static-core":"4.16.7","@types/http-aws-es":"^6.0.1","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^14.17.8","@types/sequelize":"^4.28.10","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","dirty-chai":"^2.0.1","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^6.2.3","nyc":"^14.1.1","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"^7.5.0","sinon-chai":"^3.7.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^5.0.1","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.5.2","aws-sdk":"^2.960.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^1.1.1","decamelize":"^1.2.0","dotenv":"^10.0.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.5.0","http-aws-es":"^6.0.0","ioredis":"^4.27.7","lodash":"^4.17.21","micro-kit-aws-queue":"~3.2.0","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^8.1.0","winston":"^3.3.3","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"97090dcc2affc4441b2f2afc8e5a91d247684ba7","_id":"micro-kit-atlas@8.2.0","_nodeVersion":"14.17.3","_npmVersion":"6.14.13","dist":{"integrity":"sha512-8OSeQAM/ukNjzw17zKuiKQr7YWajOHcSiaAUY2cgj4CchtaXj5srZnykaI0GrSSZNuSbTiMAMihIXV3ScEpSqw==","shasum":"354b6daff05f4f073f51b6f85d337f10b5a0e5f7","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.2.0.tgz","fileCount":61,"unpackedSize":142196,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhE9ugCRA9TVsSAnZWagAA+M0QAIppShJ7GaGDYKcKdXAH\n+kf+rakWeYevDuX2kw/aR5XSSrGi1rSN3FtfyKE8oPEYjutvmmRfzNwaplF0\nVhl6okmbb71YRhRVSGHzrWppIb39skDl6G/77yjd5D1WHqHp/M2ugfY4Vqcu\ntbhb0RFfbGHh+9rhlGcaWMWJdu65s7jtAF/62cC/2wsEEK5hPvYZ3yzvmJwh\n+LlsMbPZB3Bc7O2qKK+NdqS4DJ5S7C3HWo2JzMbmO3L/RId2xVDDLdgo0473\n+BXsOtncC4chS3QWLGLbJjLB1aEMGcLdsZid6vlE2ZkHZ0OyuONJCrJvUl2H\nGjucybCLh+ms6sB70DaY/iPWGYRvxTO3SsF0Ye6IRc6BAeOhaqXxF/oGgRo1\neyUSZGxtLXOswYYG2+dK42o3/EE/Fts9y7Os+Tj3G6RddP+0380Nq2BMZBsP\nV/vv4oeH9BRVNvkzsQvux0xiI3Q4TZJ9oduHA0QJlGAh6sZzG8zeIdzLYiv+\nkYqyexSdUcmfPunC4eTqMSa39VNzl0V70gnUzL7v6dkO6brXLba0IIWfx643\na3WjuYm5k6e/ydoszyCwNlBkhALeie4obqTgg/PQlhXoVX5F0RG4y+bgoeac\n+GTJrBfqpLdfSWJvk6m9BDYAIKc4/IlXcQmP1jU9i6tREFT8XTKYWXZ57dAF\n9RwP\r\n=L6sz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDeuOKDb48Idc9GT7BQIirsxUpIy0wZzpzXtjOCiRp5pgIgVQxu4ANA24GaY+xT3ZP4hi/DO0i49cuLv/2U6eDoGs4="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.2.0_1628691360041_0.6686538978113794"},"_hasShrinkwrap":false},"9.11.10-alpha.1":{"name":"micro-kit-atlas","version":"9.11.10-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"5598b3a5866ad0bf29a86feb2efebf48de9f09a8","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.10-alpha.1","_nodeVersion":"14.17.3","_npmVersion":"6.14.13","dist":{"integrity":"sha512-JJnAorPNiyO5Rn3tGhCAzVrSX8CMZv/vypLGK6U9dlEIQAGpkADZhP6osIQZF/VVjKdZbrVU1Vu/ExGVpXlYRg==","shasum":"324373b8c814813ae4ffe630691808476d482fe0","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.10-alpha.1.tgz","fileCount":192,"unpackedSize":772549,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhG9BsCRA9TVsSAnZWagAAN1cP/R4z3Bvaw/rjQxXPHFOl\nHrm9IbbFdQOu4fGsLdLMbsAN9KnrzdZLpy5YlFUAhP5OhdygqSMlwxRLamPt\nBr2XW48oJO9sGdq7XqMAU0cKog/DfMxbSClgw4URnuScxBBGfc0U6lwXF51T\ncjqoSyhcU7KefK9Rc3gxceDFxmdA3nta1SZB5gTrDQkovcHUVOW6RnjA2Bfi\nsxGJBQqWRrG4svL00f4uZoiwo7e3hKfhpAjM93Ysnjisl96HW8aL2kurVTva\nbP/VMjoOoUr+frbKDTscJEi9etgloekaRymFI04fHDDH3C2EuOi5+DBBCddU\n8X0lwR7EoCXry/F67Z+JumnWcYl72AbnG2a04Jg2WsoqgfjX6iQU1MB+4B5E\nSIz1K8veQK6PlXqlhQeYnJ4GS8rdDLq+2Yz2ao16aKxVcAD0Q5FzhzRRs1pd\nrNcO+ojewwwJeHPzovMe1cyStfxK+BiZGEej6dMNjqzBN7q8gMJesMuzOQbs\nbXxFIJFN7XZnQeBSYDa8tuZbDePQDhHrqvBIHm4Or5wb3DdlT8IZQOQPVhGh\nWxmiFqLOSOBJHENHYN2EQsrvw/7ni0UrbXEyOb8aD06sMYGAtcPq39HVj77l\nUsu4sPB2pn5agttAo2ghXj4aGezA3JWjtUlLqa8P1JYV5j+d6Sp3+OiqjUq4\n6eZ2\r\n=qcX9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICyxtaxdRb4xCPPa/iizPtaAyC4nL5EycED1zRPZ7tqgAiEA1wOOteOIKTA3ByAjeoJ6PN8CstJ3bZr2P5t+aIAC5xA="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.10-alpha.1_1629212780331_0.5051765410166982"},"_hasShrinkwrap":false},"9.11.10-alpha.2":{"name":"micro-kit-atlas","version":"9.11.10-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"~3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"11ea82acbb03d66d5385bf5fe7a210f30a6607ee","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.10-alpha.2","_nodeVersion":"14.17.3","_npmVersion":"6.14.13","dist":{"integrity":"sha512-o3f/5aFaucfAy1+91mZdmlkgzFsuJwNDnX8OKDpPA0PW/0nILXwnxNlPW9kg4qw2fkR7P2saCj5t3NT6BuVfsg==","shasum":"625586b8870958465eb7ff2759758d5db19f06fe","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.10-alpha.2.tgz","fileCount":192,"unpackedSize":772549,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhHRCfCRA9TVsSAnZWagAA1sAQAJSJzLehzvuEDvCZaOyf\neWsfOoc40zf9wCprYOdi/tnPxeV187RjLmn5Vc5LdYYoQNe3lWKC4NFkJ2Yk\nmcEsCyKgkduV9+TkJgN6mkDM2i7UhY24iB7Rd0WP12qgK9ZPak0lfLoK0+Ra\nHOPioMywg9NWM/eer/7Yd9uJmBH5pMihKHPLrZUlAod3Fk2IQGVk9lmCUJ8A\nukyCruOvTwc7eDy1LGJ0vQObG9dyuc/4yYg6Z/vmFTARKFcVTIGb6awf+MEF\nsquBGomDGWnCZlnBOXZLtTihyTJ0TQ/DG571cZjBoqXyChjW3f8eC84iKU2n\n/zMn4zrfiTtB6V3A2Tv8VIF3wUPmj9RmCN3UVWaE8RghPGR1ovyc6Ami2QLY\nm9UwbB5XHPDTIPIXQ+LDEPgVlVhLrKhM5UJY4CsH0Ycad19GGx7QF5j91lrB\nHq1+15OEt/p3oUj0u4ukGZAJH5oIuiFBDYCQNalBpiNuHUYchBXKbZs88Bkr\nF9yXhicVwRR+b+86+04IQ+roG0GqxbrnosOJvwrRANx5NcQZkqfFm5lq3lYV\nwmZ+9witNmiv44v2eq6Q9NPy0Fx0vGqbFCQdWw2an+cvcgneyvRms8FgE1iu\nM+n8aDRwTnU4mMkrezySV77PXB1BBFDfX3w4n32GuWK1RKHKemr8SSIEM9W1\nT+mK\r\n=9wzA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAgVc6nCobHZKAfvSNIG4XhVk0XZ9ZZmJ+V6JELzaSdlAiALRvoaINWEU3J+yVA/7QUDiu7UJaodiVela1AV4ttEJg=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.10-alpha.2_1629294751015_0.7985384571559153"},"_hasShrinkwrap":false},"9.11.10-alpha.3":{"name":"micro-kit-atlas","version":"9.11.10-alpha.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"~3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"9ee52d3ba19a28f078a596537b3216d0a1973d1a","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.10-alpha.3","_nodeVersion":"14.17.3","_npmVersion":"6.14.13","dist":{"integrity":"sha512-+3k2525s5W34dWhi0/vFW4gIwl6KphKrq12kzxcQ/qh0fRKp+5hvrZA9/RCaKEmz/4sTmUj5WAINKEywgpE96g==","shasum":"c362c2eed485d0a7dbf2ea6c8818f2eb862bdd34","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.10-alpha.3.tgz","fileCount":192,"unpackedSize":773189,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhHiDdCRA9TVsSAnZWagAA0tMP/3QU1KiRlPp2MEEyRFQH\n49GE07lFOt8CB93/SubVPS//Mh8eCBcEwfBzcPRbdPkxiA+unEcP3k4EmehD\nn2SUwjJiE3jaB2fKC2jTGppoKqSr3oQA2IqU4Hc0WTJ3sLOl3ADKtVPGHcej\nRRoHS9ZSl3HvfXWOlZAj5wILRS2SuVBk4sRjCiOP+Cf+HAYjkWomjbc8lh02\nuiFoPNJq7MLj/k5MMvyUXuR6dFdIwOROnRJWkQaomt462ZfhmFnJVuaMCAgB\nl+SvT8ThW1+SmYH+JUNGFpB0CVt0cjrASF6O5zRkXcJ/hLH1/ebpwfRbp5pJ\n6yeyiZ2aB5qjtiLZ84ArC6FswdmbibUytJ90zIUb53jAR+phce6gfF3tSNPX\ne/wYA2X0+0DWl3NDjoQQMyO23lKvRnJBXU4iniksEE7/h/JH+celPfw5Trck\n7EoJ5LV8z4dnGg7RQoGKZMhCI/R793cURhJRAZIbljeHnhKjk7dDpEr/aTTi\nhSRjVHj3LzKML7F0gpTXUsAw4YAvwUNZKBHr/gVem6jsFzSu9Oa+hr4OdZwR\nh4IrhWcW/ysJlpTNaN69dvqtGz+BmHtlQ/G5lablRKixKwnKIGMgrOhq/7bg\no2Y5FZzD7hbJuQgT8sQtUbw42q6XermWIyiQkTGu0HrSBybgFcGGCPmrVDVG\nDz9y\r\n=0VYX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDRvMoIVPMk0Ec1R/g3ihAlMi3UUDmcTUUBmyIbFbebzgIgFaN+4Q04G/N18Nu4i+y68g/oqUayQxz//WC08iEQIpU="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.10-alpha.3_1629364445542_0.30630914640409457"},"_hasShrinkwrap":false},"8.2.1-alpha.1":{"name":"micro-kit-atlas","version":"8.2.1-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --require ts-node/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --require ts-node/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"^5.2.7","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"^5.0.38","@types/express":"4.17.0","@types/express-serve-static-core":"4.16.7","@types/http-aws-es":"^6.0.1","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^14.17.8","@types/sequelize":"^4.28.10","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","dirty-chai":"^2.0.1","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^6.2.3","nyc":"^14.1.1","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"^7.5.0","sinon-chai":"^3.7.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^5.0.1","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.5.2","aws-sdk":"^2.960.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^1.2.1","decamelize":"^1.2.0","dotenv":"^10.0.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.5.0","http-aws-es":"^6.0.0","ioredis":"^4.27.7","lodash":"^4.17.21","micro-kit-aws-queue":"~3.2.0","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^8.1.0","winston":"^3.3.3","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"7ac69880fdfe6fa300647663d89c7a2db11842c9","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize, setKeepAliveTimeout } from 'micro-kit-atlas'\n    \n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n    \n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initService()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n    \n#### TODO? \nDescribe init(options) and finalize(app)?\n    \n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Support.\n  - Ajv validation (only for HTTP request parameters).\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n    \nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `host`\n_string_ _optional_\n\n**To be removed.**\n\n#### `serviceName`\n _string_ _optional_\n \n **To be removed.**\n\n#### `service_root_uri`\n_string_ _optional_\n\nThe URI segment that identifies the service, after the versioning and before route part.\n\n`/v1/service_root_uri/route`\n\nIf this parameter is not provided the routes will have empty segment.\n\n`/v1//route`\n\n#### `namespace`\n_string_ _optional_\n\n **To be removed.**\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted. \n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n    \nRouting\n------\nFor apps using Atlas, routing must be initialized between the `atlas.init(options)` and `atlas.finalize(app)`\n \n#### Basic use\nroutes.ts\n```typescript\n    import { router, Router } from 'micro-kit-atlas'\n    \n    export function init () {\n      router.exposed.GET('status', 1, async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n```\napp.ts\n```typescript    \n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    import * as routes from './routes'\n    \n    const options: Lib.Config = {\n      name: 'check_status',\n      service_root_uri: 'check_status',\n    }\n    \n    export async function initApp (): Promise<any> {\n      try {\n        const app = await init(options)\n        routes.init()\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initApp()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n    \nTo see the example in browser open `http://localhost:8080/v1/check_status/status`\n\n\nThe Router in Atlas has three interfaces, _ExposedRouter_, _ProtectedRouter_ and _InternalRouter_, available as `exposed`, `tokenProtected`, and `internal`. Both of them have the same static properties but with different signatures, the exposed router requires a version input while the internal defaults the version to `/internal/`. \n\n#### Exposed\n\n    static GET(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The express `request` is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\n#### Protected\n\n    static GET(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The ProtectedRequest (express `request`, extended with `req.tokenData`) is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\nProtected routes have a middleware check that the request has hit the API with req.tokenData attached. \nThe tokenData must contain the fields `globalid`, `uuid`, `client_id`, `scopes` and `grant_type` to make it past the middleware. A request without tokenData or without these fields will be met with a 401 Unauthorised response.\nAs a result, the controller gets a ProtectedRequest instead of a Request, so you can work with req.tokenData without worry.\n\nExample controller\n```typescript\nrouter.tokenProtected.GET('identities/me/is-dave', 1, exampleProtectedRequest, { schemaConfig: { params: '/IdentityUpdateGetParameters', validator: support.schema.validator }, })\n```\n```typescript\n\nexport async function exampleProtectedRequest (req: Router.ProtectedRequest, res: Router.ResponseHandler): Promise<boolean> {\n  const daves_uuid = '86d7e731-da23-4e2f-951e-81a04665f002'\n  const gid_uuid_in_token = req.tokenData.uuid // Router.ProtectedRequest says req has tokenData and tokenData is of type TokenData\n  return gid_uuid_in_token === daves_uuid\n}\n```\n\n#### Internal\n\n    static GET(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n\nExample:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\nExample with redirect response:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request, h: Router.ResponseHandler): Promise<Router.CustomResponse> => {\n        return h.redirect('https://globalid.net');\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\n\nSupport\n------\n#### Schema Validator for Routing\n\nAtlas offers json schema validation on the router with [Ajv](https://github.com/epoberezkin/ajv). \nHere is example how to implement uuid validation for a url parameter. First lets create the Ajv schema object:\n```typescript\n    // schemas.ts        \n    export const byUUID = {\n      $id: '/byUUID',\n      properties: {\n        uuid: {\n          $ref: '/UUID'\n        }\n      },\n      required: [\n        'uuid'\n      ]\n    }\n```   \nNext in app.ts we import all the defined schemas, in this case just `byUUID` and we load them to the Ajv validator at service startup:\n```typescript\n    import * as schemas from './schemas'\n    \n    // load all schemas\n    export const registerSchemas = async () => {\n      support.schema.addSchemasRecursive(schemas)\n    }\n    \n    ...\n    await registerSchemas()\n    await finalize(app)\n    ...\n````\nAfter that, on the router any route can validate uuid values that are on `req.body`, `req.query` or `req.param`. Here is route that expects uuid as url param:\n```typescript\n    import { router, Router, support } from 'micro-kit-atlas'\n    \n    const uuidSchemaConfig: Router.RequestValidation = {\n      validator: support.schema.validator, // Pass the Ajv validator\n      params: '/byUUID' // The $id of the schema\n    }\n    \n    export function init () {\n      router.exposed.GET('status/:uuid', 1, async (req: Router.Request) => {\n        return {id: req.params.uuid}\n      }, uuidSchemaConfig)\n    }\n    \n    export default {\n      init\n    }\n```\nCalling the route with invalid uuid will return error:\n    \n    http://localhost:8080/v1/check_status/get_uuid/123\n    {\"fields\":{\"missing\":[],\"uuid\":\"should match format \\\"uuid\\\"\"},\"error_id\":\"1adf7eae-c488-47b3-8c91-fb5942c60444\"}\n\nTo run the example:\n\n    cd examples\n    npm install\n    npm run support:schema\n    open http://localhost:8080/v1/check_status/get_uuid/with_bad_uuid\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client \nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n \n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html). \n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@8.2.1-alpha.1","_nodeVersion":"14.17.3","_npmVersion":"6.14.13","dist":{"integrity":"sha512-Mrp4hZJUB5Amg+OoGUU/IyySKWvxNvlsfy5EtFJd6bkWXaOBR3bX1c32ifzp+CbhxrazBIoWKI6BFxgHeN/ClA==","shasum":"fa283bbba491042ccd45466652afc9bd900d3210","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.2.1-alpha.1.tgz","fileCount":61,"unpackedSize":142588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhJ1DICRA9TVsSAnZWagAApFIQAJlwGsq7iuEvTxUVxKXK\nepAmXOZ4XvRA9J04uReB6gHsRZihGouwlL39c1Ah2oxkhseQ6PKCaI4rTCMe\nLE/LhZ3pJNRMOi0tuWJYkgctNb75LtDI7/biSdPuyDPAPfNzGYbOI6Yi7Gnj\nVDJEElKBdFpqc8ItmLu9fT8LUD37zo0VSaCqLhKxQlqp6qvjc/rlWyS66NH0\n+UoAPwKejiOIodPeUkx7MclVEEWPCFvVtjgW3nEZsQZ2mUUi7qqGUKxJjLqR\n33EjWVklbCXd3DLLOmMSYaEHapFP9eoFKaDVWImZyCXIBAeKeZc98+zWQsX6\nKH2I8eEIrl1Kxpk2x0ydYipK3oZVJt3dsUs6KdkFRaoMXWG+MykCm4bUO0FQ\nQPtokP5sfcuDycztPZNRHUrEL8SAQjJ+cRqsV/iA9VFHITJL+tJxTahy/GeX\nn3CJ1Lo9qDfXoHZOTK1EtocMT7uzjFDHeYzIlziQEG+s1GiEibhSamsJcbKE\nWKxHO9US1zh+TT+33I91gdsPcd++7wwyMgq3uiJHNtfd2G+0vDyg2Cd+/unj\nRdCIFQvOPtZ5MjLlh+u3ufa8ndxm40ktkLLaGrvVBOmOorKxVI165GmkCe+l\n/ZBYQ3/q/Ndjjfiq/SnwTETmCxPz68pFureAov0MUR2RPLkl6ZzlC2Yg8LoX\nDA3g\r\n=f+ju\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD+MYvYXR02m4aXxuaijJO7nPqnrQX8PHjcINFkS+gYrQIgJyyHqpNgPNOACCDVGuAVk5QjP+MZJEM/iNnKLTH1tUU="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.2.1-alpha.1_1629966536466_0.21931058313386975"},"_hasShrinkwrap":false},"8.2.1-alpha.2":{"name":"micro-kit-atlas","version":"8.2.1-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --require ts-node/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --require ts-node/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"^5.2.7","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"^5.0.38","@types/express":"4.17.0","@types/express-serve-static-core":"4.16.7","@types/http-aws-es":"^6.0.1","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^14.17.8","@types/sequelize":"^4.28.10","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","dirty-chai":"^2.0.1","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^6.2.3","nyc":"^14.1.1","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"^7.5.0","sinon-chai":"^3.7.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^5.0.1","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.5.2","aws-sdk":"^2.960.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^1.2.1","decamelize":"^1.2.0","dotenv":"^10.0.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.5.0","http-aws-es":"^6.0.0","ioredis":"^4.27.7","lodash":"^4.17.21","micro-kit-aws-queue":"~3.2.0","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^8.1.0","winston":"^3.3.3","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"101ff7ba743c85170476fc22213f4ca44760cb26","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize, setKeepAliveTimeout } from 'micro-kit-atlas'\n    \n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n    \n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initService()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n    \n#### TODO? \nDescribe init(options) and finalize(app)?\n    \n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Support.\n  - Ajv validation (only for HTTP request parameters).\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n    \nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `host`\n_string_ _optional_\n\n**To be removed.**\n\n#### `serviceName`\n _string_ _optional_\n \n **To be removed.**\n\n#### `service_root_uri`\n_string_ _optional_\n\nThe URI segment that identifies the service, after the versioning and before route part.\n\n`/v1/service_root_uri/route`\n\nIf this parameter is not provided the routes will have empty segment.\n\n`/v1//route`\n\n#### `namespace`\n_string_ _optional_\n\n **To be removed.**\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted. \n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n    \nRouting\n------\nFor apps using Atlas, routing must be initialized between the `atlas.init(options)` and `atlas.finalize(app)`\n \n#### Basic use\nroutes.ts\n```typescript\n    import { router, Router } from 'micro-kit-atlas'\n    \n    export function init () {\n      router.exposed.GET('status', 1, async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n```\napp.ts\n```typescript    \n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    import * as routes from './routes'\n    \n    const options: Lib.Config = {\n      name: 'check_status',\n      service_root_uri: 'check_status',\n    }\n    \n    export async function initApp (): Promise<any> {\n      try {\n        const app = await init(options)\n        routes.init()\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initApp()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n    \nTo see the example in browser open `http://localhost:8080/v1/check_status/status`\n\n\nThe Router in Atlas has three interfaces, _ExposedRouter_, _ProtectedRouter_ and _InternalRouter_, available as `exposed`, `tokenProtected`, and `internal`. Both of them have the same static properties but with different signatures, the exposed router requires a version input while the internal defaults the version to `/internal/`. \n\n#### Exposed\n\n    static GET(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The express `request` is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\n#### Protected\n\n    static GET(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The ProtectedRequest (express `request`, extended with `req.tokenData`) is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\nProtected routes have a middleware check that the request has hit the API with req.tokenData attached. \nThe tokenData must contain the fields `globalid`, `uuid`, `client_id`, `scopes` and `grant_type` to make it past the middleware. A request without tokenData or without these fields will be met with a 401 Unauthorised response.\nAs a result, the controller gets a ProtectedRequest instead of a Request, so you can work with req.tokenData without worry.\n\nExample controller\n```typescript\nrouter.tokenProtected.GET('identities/me/is-dave', 1, exampleProtectedRequest, { schemaConfig: { params: '/IdentityUpdateGetParameters', validator: support.schema.validator }, })\n```\n```typescript\n\nexport async function exampleProtectedRequest (req: Router.ProtectedRequest, res: Router.ResponseHandler): Promise<boolean> {\n  const daves_uuid = '86d7e731-da23-4e2f-951e-81a04665f002'\n  const gid_uuid_in_token = req.tokenData.uuid // Router.ProtectedRequest says req has tokenData and tokenData is of type TokenData\n  return gid_uuid_in_token === daves_uuid\n}\n```\n\n#### Internal\n\n    static GET(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n\nExample:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\nExample with redirect response:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request, h: Router.ResponseHandler): Promise<Router.CustomResponse> => {\n        return h.redirect('https://globalid.net');\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\n\nSupport\n------\n#### Schema Validator for Routing\n\nAtlas offers json schema validation on the router with [Ajv](https://github.com/epoberezkin/ajv). \nHere is example how to implement uuid validation for a url parameter. First lets create the Ajv schema object:\n```typescript\n    // schemas.ts        \n    export const byUUID = {\n      $id: '/byUUID',\n      properties: {\n        uuid: {\n          $ref: '/UUID'\n        }\n      },\n      required: [\n        'uuid'\n      ]\n    }\n```   \nNext in app.ts we import all the defined schemas, in this case just `byUUID` and we load them to the Ajv validator at service startup:\n```typescript\n    import * as schemas from './schemas'\n    \n    // load all schemas\n    export const registerSchemas = async () => {\n      support.schema.addSchemasRecursive(schemas)\n    }\n    \n    ...\n    await registerSchemas()\n    await finalize(app)\n    ...\n````\nAfter that, on the router any route can validate uuid values that are on `req.body`, `req.query` or `req.param`. Here is route that expects uuid as url param:\n```typescript\n    import { router, Router, support } from 'micro-kit-atlas'\n    \n    const uuidSchemaConfig: Router.RequestValidation = {\n      validator: support.schema.validator, // Pass the Ajv validator\n      params: '/byUUID' // The $id of the schema\n    }\n    \n    export function init () {\n      router.exposed.GET('status/:uuid', 1, async (req: Router.Request) => {\n        return {id: req.params.uuid}\n      }, uuidSchemaConfig)\n    }\n    \n    export default {\n      init\n    }\n```\nCalling the route with invalid uuid will return error:\n    \n    http://localhost:8080/v1/check_status/get_uuid/123\n    {\"fields\":{\"missing\":[],\"uuid\":\"should match format \\\"uuid\\\"\"},\"error_id\":\"1adf7eae-c488-47b3-8c91-fb5942c60444\"}\n\nTo run the example:\n\n    cd examples\n    npm install\n    npm run support:schema\n    open http://localhost:8080/v1/check_status/get_uuid/with_bad_uuid\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client \nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n \n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html). \n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@8.2.1-alpha.2","_nodeVersion":"14.17.3","_npmVersion":"6.14.13","dist":{"integrity":"sha512-tUvWCfhEeraq+26dFUsByPHHDaNi7VsJlxWnZHvzW5Q34bgDiJ+zniCxgSHGbkM7xhI9KQCakqDNlgmLXfSKew==","shasum":"47368d6df285839ede09c9e2c3a015a3e6d335d4","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.2.1-alpha.2.tgz","fileCount":61,"unpackedSize":142823,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhJ6EvCRA9TVsSAnZWagAA08AQAImFTNFj9huKa/XkUa2q\nlqaGRh6Il//Xhe8hM6v1S05ph+KzNP4aLX0as382SFX4dqrdMXl19BKFKCmr\nHShkV92uuLdpFgIFMHQKtlB8hYW6O6K6a8BIZemi0+OR894eayBFDDC80p71\ndQvyuanr1XDoATnza+TZI4IUOW6nvc8WMVLgSATnLucjANGz6BBKUe8b61Ro\n3W+J7GCNS2z+JAG3Uf3VfW41ctZglbjyW17LlVr2cbC5nt96PvzGfZPL/agX\nE4z3h+R/ktuBwGfiOTNGQ8Z/ktLsN5YEt8CQLOjW4ufemSRqFjMEcDNmbyGr\nUSiXb1+hoHWbqY3fpKhshplTlN8MSJr0OdLBc8Zhif8JF4wR4eErkSzV2BO2\nRWVgXwTLaGEce8PWzNwH+YkqULWlXZxFEEWDtGXmN2QnQTfdXLeqcZq8p1nw\nxMW64ihqfscou85RkGQKybAF2LfjzIps1QikbL9PkPI4z6Izg9UpiMWpibXZ\nCJpYSzIsRiaFhlnoyWUeLHZkklI65ZXimEVokNUsiurbpTCNijTkrjS19FTB\n3rW/Du38KkaqfFYiPOuFrjd1Wnd1HbTW1wotc9Kd68e0dlctnKWZcR4DemOg\nvKoQiARGnCrkXrwHl/mTt5jxln6ZPak+YNpCppzOHKd8riFheWeFjPWi6oVs\noG8C\r\n=oZZi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCMFjAMXQmv9i4hWPwHVkMgpqY2GnqV5KbuzSx/kaCa5wIhAKuyTCkij/JWryRe8tFJ6stlrj+AhEJciC/+mgYdh1Dl"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.2.1-alpha.2_1629987119489_0.5726046977273098"},"_hasShrinkwrap":false},"8.2.1":{"name":"micro-kit-atlas","version":"8.2.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --require ts-node/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --require ts-node/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"^5.2.7","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"^5.0.38","@types/express":"4.17.0","@types/express-serve-static-core":"4.16.7","@types/http-aws-es":"^6.0.1","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^14.17.8","@types/sequelize":"^4.28.10","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","dirty-chai":"^2.0.1","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^6.2.3","nyc":"^14.1.1","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"^7.5.0","sinon-chai":"^3.7.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^5.0.1","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.5.2","aws-sdk":"^2.960.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^1.2.1","decamelize":"^1.2.0","dotenv":"^10.0.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.5.0","http-aws-es":"^6.0.0","ioredis":"^4.27.7","lodash":"^4.17.21","micro-kit-aws-queue":"~3.2.0","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^8.1.0","winston":"^3.3.3","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"9957867275a64a244f92d524245f546ad514bfc7","_id":"micro-kit-atlas@8.2.1","_nodeVersion":"14.17.3","_npmVersion":"6.14.13","dist":{"integrity":"sha512-WQG1GHSHrDnjMO0SQBQBbwicqynpBede1wSE5NwTOYGZWisqpTItyO6Zw2kGNsww+8yg04Mzz+gYe6PShSwmIw==","shasum":"aecd1b8db70667519b8afa8f206a414c442e8050","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.2.1.tgz","fileCount":61,"unpackedSize":142674,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhKQFKCRA9TVsSAnZWagAA2GYP/A3ME31R/I6T5qX1XEpm\nxb54vvYTS9do2q1oSOin07xO1QeWxxM+W1ZqJI50mBDhQhvJm20vPkPjWtWd\nSMVNqy91GYsAsEPAcqAvEs2spcclz/FSM1lJsbnWLC3zi3ENG3LzHMVkhwHM\nCM/u4nr9amBWSA9dlOGY1ULaw1qHIzYG7wFeeFIw852Or+jVO0eegnNu3N3y\nLqKk+Cz/JnBi+pnUxck7x9208Ptz4zmLVKS4cnGWgdIgQle5J6ZKo7Wm528+\nHKADlfzt4bZPG3qbCMU+JyEUsg8N5uZKSH54tDAV4lbKLF2bCzLlL15ej5OJ\nQKCaUGKvwT9AAgFlFq5kRi8Bdnx2OQ0E9Oqu0S2sxZfvBKgqpL3wB1Ro73AX\n+lfplDDLsuXXe075Nn8kJZeM1X0g3n3Va+dNxdB2uW9ZADdH5bvKSbGa2ogG\n/E5jHUwGQhEauRZ9sepd9omR5ySu+NOc7RlfR5xpZ0pefwxlpkjFCVvQs57v\nCokH9EmenvAbZNefNYSACkysJTOv3CHgo+EtdhJaPAAK50biVsY/A136LWVW\nUMb5+F6tHmhWc7he3bL+58hg1+QvXv87Nn37C7C6IFrrrvq3PMGT9PdkPRvU\ny+vjxy85D/BSw35l5vBXiL+qCCN6kLN8N16FmeHExwcc414qqc8Wmd0dPuzU\n/JjQ\r\n=1hsM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEF3eHiPTob30zLXMESCQ1Ob5Wt9Jvz0oYJjwenbCY7AAiBa9vXMbFCShfSADmrXlo7BnXz3xXlqd2+6Ib0TqMCGLA=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.2.1_1630077258225_0.7934746428407713"},"_hasShrinkwrap":false},"9.11.10-alpha.5":{"name":"micro-kit-atlas","version":"9.11.10-alpha.5","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"~3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"1cb5f3ae0c1403a290d0dfda154428188eb259f2","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.10-alpha.5","_nodeVersion":"14.17.3","_npmVersion":"6.14.13","dist":{"integrity":"sha512-kNu7T4L6X+jIgZOBw3OJo58sGJRMn4nqX1vbSwowqFKdT95Ua8DrefWqYs9K7VJ2wtCE3We8Zp22xAl0cPDSdg==","shasum":"cf5be923239f13c834b3d6cfad1e8cb036f3839c","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.10-alpha.5.tgz","fileCount":192,"unpackedSize":781059,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhNxlqCRA9TVsSAnZWagAArg0P/2yuJuERft1Shae7XguE\nlSQhuNdF3b3GeW8BsAzjzbpZL5V1aKOYS0VTr6vE5U5HderNkLJufOgbOpOF\nGLvbKDW/NFSUlYNjtJ768Y3tdJGcYKJF+NHoe6hs0VJNIjNJBnX9LhQ9VpXt\nVHRVtvWlXNsM9OlIF5hl0P3gkaA7Uv9guMp7oZWBLtRdGsejG23IaFty+Hxa\nZvwko/0RwfRm1U0gGXIKHhKK1bUTCGJDCv//la+dTmV8ENbTQFjmM2C9xITO\nckH7gkH/CAteVFMUZ6hEqecyQr9ulbdHZZRsNA1XYqJ7MGSnHLBuJiYEn3Pt\nB8fsnTPUZNNal5FYJU7WdFh4B5LNjRlldQpikl1DXIzMDYAPMh0FVdFkD1jR\nQX6CtYrHbHS/pY0wBXVCv3ZwbcPlt8Bt3Z+iSoY6fa+9tT6HycMMSUDVVaVA\nd2jM/tpD2PPfCu5aMSrA1hnAiqJx0CnQ1Q6Uk00WQujuP9qngL5ipe5PpVjb\n48+o5+Tk3QozaMoEQntFFWQvZmsoGXryQp7G0A9Az2oag0OHDA1SH0o8VeNa\nDAHFDAC/IAbn1+IK+NQ/vVDhVVvOn19bDZsAdKBdYxwQXPRo8qmr4FCN5Qt5\noGOdOEZFUwSeFetD3hsgdVAoiHszest55uddCp9VDzGgnS5VcptVsznlG7fN\nWDeO\r\n=yL8V\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGLErgZEnSjvh+Cc8+SL8DOZqReyExLQjeikNgTPnNIBAiEAsOAbo6WvWsKITWHBc4ITWi/+8mu/hcYKhV19/zYMDHk="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.10-alpha.5_1631000937829_0.7336465679725817"},"_hasShrinkwrap":false},"9.11.11-alpha.1":{"name":"micro-kit-atlas","version":"9.11.11-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"7cbb6805f5cd851afc1f063fc7f1f0ed091fe9d1","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.11-alpha.1","_nodeVersion":"14.17.3","_npmVersion":"6.14.13","dist":{"integrity":"sha512-2qDsNIrJlcoL9UMu1hGf1DVBQggJaTV2yKjy+fazXGnLGfVNeOED792ep/8oqpYgJsggt5IXG7AUpeEqMmmx1A==","shasum":"6edcd3f4341f219038210800fcec137265bd5dc4","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.11-alpha.1.tgz","fileCount":189,"unpackedSize":762691,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhN2eKCRA9TVsSAnZWagAAJKMP/0hZBtZFxQDhW2zl4CV8\nP84nfKLPWEc1nb2CksO4SPVtpP1v8+l+nMn/su++geeggKGXeSoT2ihbRNxs\nqwiHlAyfRoYYUG/JYEHeZI5LpGY8WI0IDPIcRX0On5id8URmFqUThYekrRAD\n8ruFHrEXszFhpkOeAmT1tw8PPzkzy81udBRZIp39JKf6wheZGTW32wRwrM1v\n73zI56Ub/eQLB3bZiwc6IhYG6B2GEziBnyRSpqz/OEBj/ud38x5AxbQBB78Y\n3fyotEs2pFiw4hvBrkpG08xFaexXGV7gbdTeXFEbQuVu9TlEykGZkwy3uOdG\nt/Ntt55blC2J1hYp8+qCHjSYJQNJ7LsPCPhrb8iOibsui/P8CFiCFEQEDCSw\ngamh6yQ21tiT83mutHobVpLRtujCF+76nwjxq7XQ+sYA7anOnOcVxE5kZnC5\nH+uW/BiAKKBDXmHomT+l5we24/UuqXQyYrMbtU6WjcRLdKS0/xgA1BKBnyTp\nxmsRZ3U1N5u8Te80YqKuqBkKgGofExu6glmIwATli1XEd0wparutZ6EKsxSD\nyNcO0xroGJHQVBSIs3nRa4SWdnMaVHDY/lQHowVhLSbuMK1lGMg8EATYKRH/\nhfqRHJh6oxLXlzjW5KLqPk9b7OwmhEvhdHcnLp6e7cziAKFrD0R9rkBbqtYI\n6DdC\r\n=DAHv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDIduc9MUKVzThvapyF7vFhA+8eX9mGuc+Z+IXtdNFHRQIhAOWaXmTe8JV7XDuTfce3+yjmd0o31SzTdX4r4ja9VR5P"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.11-alpha.1_1631020938019_0.6658474782761079"},"_hasShrinkwrap":false},"9.11.11-alpha.2":{"name":"micro-kit-atlas","version":"9.11.11-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"d3c60820ab36d1835c9373bb5a7f7819c6d06185","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.11-alpha.2","_nodeVersion":"14.17.3","_npmVersion":"6.14.13","dist":{"integrity":"sha512-MaFHF89vuznlHgYT/x591W/dYLo+lzaaXYixWy7QT7mnB9RJEI8nIY4sA8orL0iS7++0kKJhRFN750prp0vMOQ==","shasum":"a37d8e9ac21a6a07cc624324f03006f7d9fe6630","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.11-alpha.2.tgz","fileCount":189,"unpackedSize":763518,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhPwSrCRA9TVsSAnZWagAAqv8P/RxTHofNdJLoxBdsZ8Is\ncmw2OOYwIzD5upXLe8hRgkqZO7rjea39U8qgOr2zcYc/7lcKsTqmxdA9b4k1\n4rIXjFMXWP924gp3PVBsXJT3gfz9DcMSFzQ2tkgp0MKwK+xfjujKqTWO+KEJ\nZwUhIvTXBcnnlrF9pynC5bDdcgqiskIbod7t0clWDfbzlYMC/e4rppYsBslB\n+MLljW4BYeRg5zrIlD/WGI0eu6d8oV1CLIPbdya93R4jef0Wxxr9Xysm3oHl\n77sjFa/mwBoyzACAxVwODX0IiADPktqwtVq6FYW9CTfdsuilMheDC8RKRG62\nYbNifKjhiU9IJKV3XNGQeMbgAulN8057BUcAc4HNLMfp8YFz5ATxF48DrPI7\nUGqou4vLWFrilpznu2qvJTSnFXnH4sdtHrv9GViCHSvFX24THkkPpIS83ZSf\ncdS/oYx2Futx2h9lP6r+3tSFhkUp67rYTJEalmRP8Nj2DjEh434yU1sLx+CC\nzDBcRmm6gktTtMG0zeU0n/GLFMMAf9RZ20mMsp1ec5DI2lMf4iaQ5WTOzuTa\n8Uhc1zXFyZsKAbd56c3HZPile4z/7YNa6IbYK3bImyKVhQ5j5RO/cAHA4Q9f\npQeAT5KooSUaU8wfopHZvXmp8fIS5X8jhcNGvbYseSSYa1J1p81v328Kem86\njVuP\r\n=dLi/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICkEWiqjdkL/wwn2rP1m2rv1Qh0drPuDCKLCWFIjwqlKAiEAhf+4vp/f6Edg79SP37miUlhHZcUlk21HM2dX7n+vXN8="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.11-alpha.2_1631519914945_0.1864321721932416"},"_hasShrinkwrap":false},"9.11.10":{"name":"micro-kit-atlas","version":"9.11.10","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"~3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"c559c9b16fde0a1973bacc5c6ce1aaa180135725","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.10","_nodeVersion":"14.17.3","_npmVersion":"6.14.13","dist":{"integrity":"sha512-H5Ehaya3RFnM33CzhcaN8qut2zreMJ2FfuOEujiJOOpRehn/nzht821swFxU0AXRWCI5Hc11YTJMdfAS0N5Uug==","shasum":"4dd029824db31327d59be9c5f97cfe9ffc73e77a","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.10.tgz","fileCount":195,"unpackedSize":784498,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhQJL0CRA9TVsSAnZWagAAKJoP+gMCtiAmpDF1CMjCLu/u\nE1y6owWA14Fqdbop9886rUxPe2VyJes3iMzs7y7YaviZLDLujkygf+/JoHzg\nAZj+t0f4IBGXg3au3r2yFxAFvllgbucRL2Oh+rBsAqW9BhB0YJGgSMaKNuEr\n8KU3zK8F+2QSTcRb5fUYyjb2NsfOHomIxDf/6cn7PEc3G3qhFrxIWZt7lkZw\nJva6wIGz6Ip5BgTQ2E30fBhraYG51P4XpHzgeXQt7b2nb9oF1nl4ibV5Xk8N\nWAc/HMn25STe6G/BszWEjKtXKfq0LEjCRGndzSnwgb4vQY1GASlWq7XqN1aF\ncJtM5HjrMNevlutxq6RpcNDAZJWcyuM12zR+ZnYHWu2pQEDnCub4a14zBNUv\nBlSc8zYq/MjT7Tqtc5HBJExB+qKFdCmIMyKnrRemgkZn0AZAVCDY9U8l0KM9\nsP3I/w/n+G+DK3PETlBHQpT7kzWxZOgdblYwBJ0iN51PQoU6X7v4Q7/2BrhT\ni8H7ew553Ldudmogg0cqZ1bN9l2EN5pSEkUzucwoV208uevRQ4cxiRToOKeQ\nGdoKkpYRJtCJWSPCOfIJ4A5LhfvBqHzu+JGERuhGt75uD8reUpe/HWU4Rd3B\nXWiBZQsjVNWEGgg4rbIV3e6/hO2g5mt0vcNO6CkIXQgVODDEg/Xug7UC5YaR\nRe8d\r\n=N+zm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDRfzs2uj3PCxz3u/2Aw1XCy9+/Sf8/Fsp8V713tF3V+wIhAKt1hJJ573k+njbTQgxsPJBHdTxNadszI3SdFe/SK0xl"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.10_1631621876664_0.03474502585938222"},"_hasShrinkwrap":false},"9.11.11":{"name":"micro-kit-atlas","version":"9.11.11","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"~3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"5b2724f826ad94554c2717a26f9c37588fad963f","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.11","_nodeVersion":"14.18.0","_npmVersion":"6.14.15","dist":{"integrity":"sha512-53WiJOjvRnX1lBLT4vg7DTDTxqgiflrtpj7HLlHSG/p+cIIRYGm+lDPOhjwCfAiY4GiMzRsIXMDsWfPJdXTC7Q==","shasum":"aa4b7bb74e7578c573df8b7fa04b99a3ef0888cb","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.11.tgz","fileCount":195,"unpackedSize":785017,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD26YeCyHvEQeuZcHy0L76X8dZ13O58gDInG6fA4FDjBwIhANJ8Ow4ESxqqTX2wHXR1ACVkCT/fAXt7GSC6gU4BI+sr"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.11_1634030955001_0.8140793569893034"},"_hasShrinkwrap":false},"9.11.12":{"name":"micro-kit-atlas","version":"9.11.12","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"~3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"bbadcd2a75dd27e392c87c7da281847e1471bc8f","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.12","_nodeVersion":"14.18.0","_npmVersion":"6.14.15","dist":{"integrity":"sha512-hQzkAjC7uVhUbHDl3o3ilOPuQRdw0ngeSG7/8in5JXTrkTyysrUacWhf5V99pHx+SdWdlOXSySLIG5k+wleXGA==","shasum":"7fa00bccf47417a93ab0fbeb909d2aecb1902f78","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.12.tgz","fileCount":195,"unpackedSize":785275,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCaHXnD1DDAg+J/u6piXFRns9YC/afj2zLFmDbjh9+9AAIhAIDYjerd/YxvTp+YE7llNo93ICX2epPLiQBC5XF0hvQh"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.12_1634132349869_0.18380367997644753"},"_hasShrinkwrap":false},"9.11.13-alpha.1":{"name":"micro-kit-atlas","version":"9.11.13-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"~3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"eaf768966151793f97471687979b8946e323b26a","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.13-alpha.1","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-qvjZXW/Ftmbou+OsPw40ypHTdw2zWXjT9hddZUKIL2w7lUUVjyC+UbjQUmSlYxvvxbdfIZ2wiC7/SLO77X2/EA==","shasum":"64c38142731afd1ebf8dd43f73356ef76e8c498e","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.13-alpha.1.tgz","fileCount":195,"unpackedSize":785839,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDOlFhNuRwl1IG7Nv+exlexHiB/mLkM3JGlhOwo+wJofQIgX+rC/obb/qzr3TJYqJTEouSXud0z8YUj3oSy6oQV9Ew="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.13-alpha.1_1636100518697_0.5249675755966798"},"_hasShrinkwrap":false},"9.11.13":{"name":"micro-kit-atlas","version":"9.11.13","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"~3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"d0bab6b83c4eb80e2c568e2db7d12b230827b3a5","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.13","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-Zne0jdOPpQpkJcKtkR2wEjNN8yIWPkCS1gYytzKFah021MWVKl5IuVJlTyz0WcZ1ySRU+l0XubQ0b9skAo5r7Q==","shasum":"bf4cf5548b97898d511fc09134eee5cc1ae2180b","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.13.tgz","fileCount":195,"unpackedSize":785831,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICDAnD5ipCoPCOuh76FAmf5wkH7VZg3R5CDXy7Z3SuWCAiEAi4JJ5aIkxMr4djnsuKqyDl87Dt+fwWd6kZ8z/1G7o58="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.13_1636108730051_0.9534856255709738"},"_hasShrinkwrap":false},"9.11.14":{"name":"micro-kit-atlas","version":"9.11.14","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"~3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"3dca342eb24f66213325a415f5d1571d70335d6d","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.14","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-XiuIy52ESV1Y3thfngyt9AkhBJJ3h3yXjvJ14pQrVNRX7ciglZ5egP9sVBUJsesc63EPhymyROkhZn5bN60Vkg==","shasum":"042eb8b9b5f05217516a5d89c429c5353fb69a1b","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.14.tgz","fileCount":195,"unpackedSize":788395,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhn5HMCRA9TVsSAnZWagAArhYQAIB9Qwf/dTTmr/I0MSEB\nKFsj9042gCQ5YOEN+TdJNvk8+I2o5TQmTvxWm7I9OA4G+qW/qQWboa4aofTi\nITF1V9dE4GsfqhJgrbN4Y74f1J+/wdCl6/HG9tsXq0PP6heQFx4Uo3kGIsrz\nABuhAgh5WbLFu+Jyjb7goOGjZMrFPZ8p1EQBf2zJ0o8XN/Ifj0T2jLpmTdb5\nUM4uj1BPEBT2Nzhm5pgspGF5IrpeDXeW6ztmEVig4D5g2/K5fjOwgYQ2ecUD\n+lFttqJneB5Hwphl+LSHOnPYLcAVf0BXr62AQW4CPbcy6UIdCeusgXfqg3M7\nkgQD6Ym55meHY3qJJxh08r6Q4VBEEm+mN14N18Ru5fAsvpDYwtRsWzIdKNxy\n11+8O8XW/HoQS2YcMxrCo9WJzEMVTiAIWG/rTxEx2rJ45tqopF0JQNAPfPNf\nFYuJhiWytdsaMDhN+sI5OfTuopJnxoUYV0bNK4BrrTmIMzj/IwrLGfLkRXT8\noubF6fRWOF+2jfJ67Cqwaki0PgM5q14dCXjtlo2GbHDPgwTeiy0UqFM7dsC/\n3Q5pqM1radX9XwwYjOXkkyzpa9HVbcU+ACqpTqCDg+OyQKUHczgDZiY4ASBE\nvPqv2o5ZX39xbYRPIl5lD87NjybY2YmwZL4YIi59P2wsht2LnodlsBhFWc4N\naU5W\r\n=NG98\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICvdgzYc1BMO1+bCibDSKjHWL1PoJf+0Qv6UPG+jObIFAiBFPZlxIlY3MXZQH8WSjMHt53YEJKqg83Kwug9972vu4A=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.14_1637847500130_0.3929450773562666"},"_hasShrinkwrap":false},"9.11.15-alpha.1":{"name":"micro-kit-atlas","version":"9.11.15-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"~3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"a6888995acd86e65702d3dc0b6591cf81f3b4f6c","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.15-alpha.1","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-ySKMCw3x17Qv2NqexnqzKtD3Q6JjxaSun7jQ+EuXJM2Tf/d0oxFtv1/ZJ7PiOi8RlxG8kB/f412symdFs4E28w==","shasum":"25f69c9e549fde0a15f76ddddf587678fca514ca","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.15-alpha.1.tgz","fileCount":195,"unpackedSize":788827,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhpl4yCRA9TVsSAnZWagAAZqoP/1LGoNWiufRKF6UCenzY\noZAuFokETruhvtjL3ZJx2U8zLiZO+KjnzTKcicsyRk0EzI+KhvF0L52wXbqq\ncCqb+3RLm62/hng6sm+g0I6GT7WO7yhV9Bb/KXxW33423R91e/tDlfod2kQf\npKnviJBpUpANVkag1I9B6SA3McRsnXdW49Y1bwEWpyxVfzRC8tzZ9a6tWEL4\nzDTd6WhdiiAcBkpxPMHLalDScJa77H5d7bTMhxmd6AQQ4IGn1WdurHlE5z97\n/CF/flab+s0xmc6R40/GE7AmvwHbVKUcmRE/EKjIok5xhWrV9i+YHEStjbwP\n69QH5TZp/EWPH81q0TuyaYqfUrYZYtwzGO7zpmCZez9h7Xk+48cQA0+CYCFP\n5arsj8Tv84BDV9xyYRUuURQRjumQELzYl2scfSHgZt0JXkmonRJQnmdav8OC\nkqHWziFj0pTwa2oZ5p1VQwDyp2bM4wacPCDN2kQRBOYjbQj6Fdti0hnZW7nI\n8hjtAEfEIBr3+PSREq8E98pnnhqaWu9TB1RjwKclT+xILLHVJM3wNof1JXSP\nYWRueHwWaB8HN5ydW6ITxF1FkiqHTRu+QkA/63shRz9ghDisWPLSgvTfc6Aw\nGQWT3b5IVFk/pKOPLGthQ+2w1OW5tDZMBZ5JTT9OueZRhZ3EDKtZKoE20P31\n7XPn\r\n=Ziko\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAwVFgWjvW5El0Vj+wuk/kudrDklnj1SC/wKnuSHYKGGAiATSX0OoWx9DhVE6owI0xf2k0Y1xG7aO0Vzkag1ux/JiA=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.15-alpha.1_1638293041813_0.6562945606897403"},"_hasShrinkwrap":false},"9.11.15":{"name":"micro-kit-atlas","version":"9.11.15","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.35.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"~3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"a6888995acd86e65702d3dc0b6591cf81f3b4f6c","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.15","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-nz6j3StRfgkPe9pU2et3YfDPRnpY8z8Cvw872nmutIRgGEMk2jl4DVsWte6MnKTH6p9coUpKILp3VzuMvGqGpA==","shasum":"9c49eb2a1200db6bab1eccb00db8499a1b4a9b90","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.15.tgz","fileCount":195,"unpackedSize":788819,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhp4rlCRA9TVsSAnZWagAAQi8P/ii5rLzsKoRMkNdtjBDS\nHZY86jxtwyVRB7AxBS2EXyBmVQhLERyHm8q3Jkr9BkytzL49IoUFiKGJncGA\nr2hHlXqzOfGkXDwQoIS/CIzcei8zfL0gSwZpafZAMYHuh3uccp+ftHDPOh62\nInz/yDgaA/YVRVp0rleXhu9AxsEpE0KfIGrkmthjSwPsuEoClVSUfUKJB9dQ\nSAWudo+YsG6IBKUBnX6EGBKIlckC/fOjshbXc6tQl4yk7IQT71Zb1xtU8s+r\nm5XMZ2rJJBNsGGBUSrVRdpD/LwtWAHZJk0zPdEWSswYQQRdKCxUs+2GuNeLS\nyuTRt1gVo1TQ/gX4KhBv6695ktxJPl9CXVDE8qqzr5QVvAfGexgzDcFUuWdZ\ny9Cx2g8ggOlb6vjQ4nEQsel1naha6KvPkKQ7Ubdt75Fs4xClnQA4gltYLJNp\n610huPUvSE6ZvG/kEigh5ZS/fy+r5dY28CdnwhqsST6Z1oPBO9ePwCnf92qk\nB8jUxKgu6fTDhslrL3CTyTTZierx2TMcLpqycJSV8CEIc6PXb7A1xn64gsr/\nTEPztbKRU/Kya0f0q46MrkJLSb88qVD1IzWu8iI1KQJf7rtC/21BR8RVHNUm\nz92n34QAwRDxizqEoKKkr85YDloViaRhKCN3nRT3yGF9Peo96sH66bh+WKWI\n9iDD\r\n=R2qf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD3yLOgA4y3kAgXMpZoPjk0oepVtmhr8TBeomIrjMDsIwIgJnabe/OVUNhkkrcqilRr+dQBql2raFNExEUqGcVmxiA="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.15_1638370021716_0.4418126909352773"},"_hasShrinkwrap":false},"9.11.16-alpha.1":{"name":"micro-kit-atlas","version":"9.11.16-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.36.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"~3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"eb4291024868e29f6b0ea2a502405fd0cdb7b9c3","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.16-alpha.1","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-loZoQcqk5SeRj+g05sDUhenliXZJcwhK7MsoFiB+vL23dh9AFcFZ3navqBLve/tyaRGZ/U4EsKMlPWlIFqTxCQ==","shasum":"c81e4bd25e48bd7c9ecc965f8b973eb0afe64a10","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.16-alpha.1.tgz","fileCount":195,"unpackedSize":788827,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhu2WyCRA9TVsSAnZWagAAGC8P/jbaNJowy6J0FERXw+qY\ngP7ZI7FP0QGqsty5aII4eRvLh+udZU8SCJyjT3FAonc5DbvaDku0pMe/N5sf\nrjl8GMX2/M+c4R3DPs0PPAv/LaYmU4WEknQcbF6y3iqP70QbFSHmkzu0jqde\nACTfa9e4VzjZ7QXkHxPTl+t+42nxn0ci/WRNkIITIzD9mkJTiMznogVuVVDO\npfSmLHuw1PdCioMLb9d+1PA07xoleN7SP6A4VrnCpmOICKD9QWY21bazFq92\n5DG9AlGf6AQLizg7YXSVu0fO0tRp4/OOArLaFe1OOLlIQC98P9Wnvse9rsZ8\nDtxx6Lf2dROsqjgoKOOeAv6L2gPZzPzUtQeZKQscHXg3RY/5a8IkfwRi+G9A\nXsyAgzESNIbGhFGUevpKCTITIGHUwkPyBrbHb0tPwrQfILAiJrU40+fAIglo\nM4+HN/NvOJNK6J4UrAVQW4zR0GbZLc8k9TvrvJDmlpfn+R+yPufPZgoYk2ba\nzTn6OD1R8IFpZhUaiiVnOEkP01sTWvtAlRNCxcvb73PQEvOKLxD/nRG/5mv2\naulTJjXNvhZXJW0GK93yaf240726kjKIPaQsS1jrRhhlbCEDUxMX3GB6+ec6\nG2Rp/TjdN51exG6VItaWIUOYY61zPwLURBXs0sbO6zFlljW5wfF5hqJpIVM6\nE61t\r\n=XEY0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCycDeQQFv+JZO+0sEoC+tDyHN3hA4tJbguaItMVD69FAIgPh+nZQFZ/hju+W7kLYgxy46r2OOcHbCndh7Oe1Gk7Fg="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.16-alpha.1_1639671218755_0.23698990778795226"},"_hasShrinkwrap":false},"9.11.16":{"name":"micro-kit-atlas","version":"9.11.16","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.36.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.2.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"~3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"3c391c7e07f1a81a6c5cda7592e357fe3ff8f75a","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.16","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-oxEt2LBL2+kcih5zeU6za97vAMHoS7vFUB70Z47eXWseh/V8aCoI4myrtuc1XY7Wfv1mI2xuG5HtRwCtCX0HsQ==","shasum":"539027b20a798d7252d5fd2230a48c700ab755c9","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.16.tgz","fileCount":195,"unpackedSize":788819,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhvHbOCRA9TVsSAnZWagAAc2oP/1OnH/39q6wQDThOAuuf\nJNi3LHD8kl3R3Pg1oeJauZVeSlsIDvdpVYaPuvVb7sgJ4y98Vfs4uJsNu1pX\nejWs5IoDmoTrjO/ytMJaE1Hc6iN/kKmne/icaBk1gcdF+sVLLpeHyuu+2yR1\nzEH+ZkixjYdzWsyaFoYOlmDp8rU+6vXFDDh4KpMCPc+PyoQrpXvpKshBDHaJ\nJTUhfmQRDHZiAkhHb0AvoUOVRRI63gnic4m2d08pfXNM2ZoD8NmTkC5QOHlL\nOnw2uL9yzg/0Dk/5Qvxn+4Xk4tbC0vLaUbFx2hfOFX2GWivcGDJffqyDkBqr\n7CfPC8xMUeCey/OoqYqRZ+YE7im2Y21n9WGhYvEV/9jK/Hw3jZvPK7Ui8g6+\naThi3Om3Eu+fr/7gDW55tvqwqCWA8cRlyfYdD/TC2YHjiuWRdW60ObPxldic\n70NEc5AyV+xcyqme0L0IRODBW3JqhUqvCKxqsA9nGXRnzQstY3ilB1degzyT\nYu8msYR2RiOYAaZRpr763KpvB24cgosrWS/OwdvzAntGn3EUyqJ1ptnJS3jv\nVppQAhZ3CgFhkrzCH9QhImPYv/r5KkfIRMkUp29KgPhSFOisVTUb/SujNHgo\nC7X2umMol1APkAAfuRf/HjBjOlQyrrUL8Y97oe8H0MZue08mMOs8uJLY68YC\ncd9k\r\n=+Uy+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIH4swA4R4VjzrTtln/+8jHi0/EIV5SHcV9EQ7wLX3FtNAiABfM+kg6BX900m3yfLYE/6O/NEz41veUa6UX9F3Snhcg=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.16_1639741134271_0.2815591734150802"},"_hasShrinkwrap":false},"9.11.17-alpha.1":{"name":"micro-kit-atlas","version":"9.11.17-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.36.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.3.0-alpha.1","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"~3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"4933be666c34cb4628ca01862ae38eaf5cfafeb6","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.17-alpha.1","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-J9gqe53UIK7oqG48AjR/F8zcFuHpeeg4E55lD8dfRVbuADeVZW1roM8NpT/SyRtwQBt5MmD8t+x/NDUZVbNJyg==","shasum":"ac096b151d70a741bddaac1a7b5efbabab539a60","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.17-alpha.1.tgz","fileCount":195,"unpackedSize":788835,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhzcjACRA9TVsSAnZWagAAX2EP/jY08AA8lgkSdzfES0s/\n6ihTET+v162adbBGnqwgV/cNiR6dM59WDX2q68rz5LIRKBOwWgtSdLP4gRep\njWccyu747lW/cm8X0/iBATfmdwlEvyd8s+tatlQyHa9lALsXUKWrbDEy+hiL\n48cbDSSoFRXh+RFZNKlUqfGjhESgB+3tr2hv0KE4L2f6zHhdXY0IXSjIB7Zr\nNV6LLojpxniq/K1D5k7iA4I6yd8QEJ3zKiFb5g3vcuHhhUXdloh9TwCEMkHB\nCOtlgIEjyuEyOceB1O28rjNtXecjQ0fFLSKOcxui8/WXQdbkPhK/goIwPWN5\nLHtd3H4uqtyE1IFLRhr5sV4N2w5Z31yfDFJVN1Oq0VN0kOuSr+sGHb7Ipfpb\nwJiW59waAyRTX6GgmlC3K+uB6xJU2NH7FLgEUsP/x2WDPIv6aND1FAu++xPA\nG5sjKFcb352JtmP8O9pMjPnxAgn3bDGrW4HNsSBpcH43mMs50hgBNlq0SLSJ\ng3YYiM/DGrZQOsiWIHJ6hU9kX6OTqubOdxmQnG5WwxvvXbegc+W/+JzWiGEn\ndG0Y4chWPCvq+D7jCRpXwlxggpKUgfqBGGLgtLZ9nVn2wwPHLmzQgflF5Vjm\n4rjxR8u9CkHThpWbRbw7SmerAnHcnyxUBEcDRJ1/k96SyeBfUGCKZHM+Gzcc\n8P7G\r\n=mJur\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBUECEZVB63jCC62fGkYBECgfDLDsvtKgzRIwL7ZWEuUAiEAxyMHitUVqV31052j5xTRSazP6WAXEPAKmuRyj1q1M78="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.17-alpha.1_1640876224059_0.742673179342068"},"_hasShrinkwrap":false},"9.11.17":{"name":"micro-kit-atlas","version":"9.11.17","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.0.11","@types/chai":"^4.2.19","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.12","@types/express-jwt":"^6.0.0","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.0","@types/ioredis":"^4.26.4","@types/js-yaml":"^4.0.1","@types/jsonwebtoken":"^8.5.2","@types/lodash":"^4.14.170","@types/mocha":"^8.2.2","@types/node":"^15.12.5","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.6","@types/request-promise-native":"^1.0.17","@types/sequelize":"^4.28.9","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.2","@types/sinon-chai":"^3.2.5","@types/supertest":"^2.0.11","@types/umzug":"^2.3.0","@types/uuid":"^8.3.0","@types/validator":"^13.1.4","@typescript-eslint/eslint-plugin":"^4.28.1","@typescript-eslint/parser":"^4.28.1","chai":"^4.3.4","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^7.29.0","mocha":"^9.0.1","nock":"^13.1.0","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^11.1.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.19","supertest":"^6.1.1","ts-node":"^10.0.0","typescript":"^4.3.4","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.936.0","axios":"^0.21.1","class-transformer":"^0.4.0","class-validator":"^0.13.1","class-validator-jsonschema":"^3.0.1","dd-trace":"^0.36.0","decamelize":"^5.0.0","dotenv":"^10.0.0","express":"^4.17.1","express-jwt":"^6.0.0","hot-shots":"^8.3.2","ioredis":"^4.27.6","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.3.0","polly-js":"^1.8.2","qs":"^6.10.1","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"~3.0.0","sequelize":"^4.44.4","serialize-error":"^8.1.0","sqs-consumer":"^5.5.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.3.3"},"gitHead":"9f31fb36f5c4dc3cb13141329db014e832bee9eb","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.17","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-QnMbH77WyQql3qHxOe0m4z6kUHGjoyw19W6EbXPq0e44KKK22GEyOHxCDrhlaXSVMM9yp9uv7TEOIBXHGV1B4Q==","shasum":"7a5694d1a549d7921ff79fb2ef8b4ba36cd15d14","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.17.tgz","fileCount":195,"unpackedSize":788819,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh0tNWCRA9TVsSAnZWagAAV8oP/2oVqyX4je5Yz3H4aP94\nLrKP1pH9EQxEBc8SbQU4/qDIUBPJANC5nOXOgULDzYK8LsmDezLiLggPRiCh\nPufmi7Xg8qgOozWBnkli+Qvdi2y73TmgxT3zibbXGiAHLUHp/RZATq9GPWkL\nyA3u4BchG+gkQgzPYOlntkMk0tzeRqQ+X3dUHkoxtDPc1XYvAHPJt56Utqto\nwZxk05jCcqP/AZquTUiya2xiPeTTy+QfNFNLotdpW/7zmUZJsVVYkK9wk5d+\nZbBVcxgOFLGjMLbaAYs3WM4ud8PPCvBRj8tFAXjha/ENj9dnxc0knZe4BNmP\n6lJ5QWo9uGbuJfNwBOMjLeEBu9AdnFQXjXsT09Mxg59NyWr62+HrcxktL78+\n6a2hkk6Z3Fid15/S1E5s2uqc1zUrgknuMWcbr7SJkNVaC1KrPUvpgUOBohbf\nwEMBl7bpHgFGc83TDwyjqNVuUnwP2Mn+pTiy78tuksV0IrGImuQ4kuPK/LB8\nn6ga8fRJ7S0x13F0+Reuy1gByr8gCOgYSCHgJH/oY8w0tH3NobIk+iOh1xwz\nnri7/QY30cbnz7rKLqPrftCzYeSHVMnXVzDZCEGDd4GgbvIl8ZChV+UuK33P\n5rvERDtUV9saSeIQuaHVE1GWN0wSx41udDWv+Ml/TXmzsQq/hHT99O9DkLUg\nCa31\r\n=SI25\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC5PMfYYzJq1gu7QbToh/gi+ClIyqFxlRFMBGa7W57HOwIgNJkIoGAj6lL8GcfvBNEujCoQI4UH4SHv0dWjViNy4GA="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.17_1641206614520_0.71766242226207"},"_hasShrinkwrap":false},"9.11.18":{"name":"micro-kit-atlas","version":"9.11.18","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.2.1","@types/chai":"^4.3.0","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.13","@types/express-jwt":"^6.0.4","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.1","@types/ioredis":"^4.28.7","@types/js-yaml":"^4.0.5","@types/jsonwebtoken":"^8.5.8","@types/lodash":"^4.14.178","@types/mocha":"^9.1.0","@types/node":"^17.0.12","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.7","@types/request-promise-native":"^1.0.18","@types/sequelize":"^4.28.11","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.8","@types/sinon-chai":"^3.2.8","@types/supertest":"^2.0.11","@types/umzug":"^2.3.3","@types/uuid":"^8.3.4","@types/validator":"^13.7.1","@typescript-eslint/eslint-plugin":"^5.10.1","@typescript-eslint/parser":"^5.10.1","chai":"^4.3.5","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^8.7.0","eslint-plugin-import":"^2.25.3","eslint-plugin-mocha":"^10.0.3","eslint-plugin-prefer-arrow":"^1.2.3","eslint-plugin-promise":"^6.0.0","eslint-plugin-unicorn":"^40.1.0","mocha":"^9.2.0","nock":"^13.2.2","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^12.0.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.21","supertest":"^6.2.2","ts-node":"^10.4.0","typescript":"^4.5.5","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.1062.0","axios":"^0.25.0","class-transformer":"^0.5.1","class-validator":"^0.13.2","class-validator-jsonschema":"^3.1.0","dd-trace":"^1.7.0","decamelize":"^5.0.1","dotenv":"^14.3.0","express":"^4.17.2","express-jwt":"^6.1.0","hot-shots":"^9.0.0","ioredis":"^4.28.3","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.3.0","polly-js":"^1.8.3","qs":"^6.10.3","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.1.0","sequelize":"^4.44.4","serialize-error":"8.1.0","sqs-consumer":"^5.6.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.4.0"},"gitHead":"4b8c386025be025085633759064b964d8e480002","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.18","_nodeVersion":"14.18.2","_npmVersion":"6.14.15","dist":{"integrity":"sha512-oYADNSZc1PEEG2zDYAFpBn99ynHQ6OItYbOQEKixCROdH1a5RRtF2HQAJbMbxeV46gJ1PECespT5IMCEpIdw/w==","shasum":"0a7a7065eed9955f6ca7509b44eda4e1b54e3eca","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.18.tgz","fileCount":195,"unpackedSize":794944,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh8QnCCRA9TVsSAnZWagAAOLcQAIYre9lqIi1oa+8h826d\n6qw4bLLmiuYgStM/Bxi+6G9uJl+jxMS2+jA47jN6QACxzwU8tHVn6SooXLSA\nsGfaqA9MeuRMXSFQgYu1xDwqTGklB3/8C17Ub9VRXly11lgWqUVdD57C0PqN\n2RI3keFj3I1bcOpP38KHBZsWxW5kIQ+pmuVjP+VnjkcsN3tWvOkfaIRRdZNO\napB58x6BRrqeOpc6/cS42WFg4yCd0/XeyrrwjY/igmunw7VgvyaGB+FTCdYC\nTL8kyJzQol3H1EspmQE6P33+30MSN7eKoUxRWY1ZxHCvk/AGLS8MZy1Gtx2/\ni/Y6Q8knY5DnvpCIW4fbAtnvbHn2uLCSBhFYBAvlocq6PuMp25L7NoH0WWd+\nAM0jAdcpYtpS1Cja9ttHdXFgvgJzjnJPJ2ryqpLpMkj+cdj8pyFopgFg6niV\nl2dZsdG+kd3dLSdTXx92rfz6CS/i/obo3EFFAYCSUHE2FUPFUtADzb3NuEJB\n6QvHb9iOh4QTIA6rbdZ37+rEdvvukyRSHI/uCdKO5XErbiu30+gkBKEkiQ+l\ncDegUWajfSjLTbvPLGoum5x/VUJwVN28JJpytz3zV2jJ3zMnZj/bPaONkw7S\nCguFX1LV6Xc0r8hcrVcocuaKTmhgyn60wd+MeLGIF1jqF7pb+mNjKIproYxW\nDm9/\r\n=gU5s\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCsVLvnzjotO1g1YyGJgV4t7Vkcw+/KnYzeOz/7RzxVzAIhANmwmOc0jhn6ujQ6oaaR5wINPlg/5PT0TU5lOzpmcZFk"}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.18_1643186626744_0.15972345281893618"},"_hasShrinkwrap":false},"9.11.19":{"name":"micro-kit-atlas","version":"9.11.19","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.2.1","@types/chai":"^4.3.0","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.13","@types/express-jwt":"^6.0.4","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.1","@types/ioredis":"^4.28.7","@types/js-yaml":"^4.0.5","@types/jsonwebtoken":"^8.5.8","@types/lodash":"^4.14.178","@types/mocha":"^9.1.0","@types/node":"^17.0.12","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.7","@types/request-promise-native":"^1.0.18","@types/sequelize":"^4.28.11","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.8","@types/sinon-chai":"^3.2.8","@types/supertest":"^2.0.11","@types/umzug":"^2.3.3","@types/uuid":"^8.3.4","@types/validator":"^13.7.1","@typescript-eslint/eslint-plugin":"^5.10.1","@typescript-eslint/parser":"^5.10.1","chai":"^4.3.5","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^8.7.0","eslint-plugin-import":"^2.25.3","eslint-plugin-mocha":"^10.0.3","eslint-plugin-prefer-arrow":"^1.2.3","eslint-plugin-promise":"^6.0.0","eslint-plugin-unicorn":"^40.1.0","mocha":"^9.2.0","nock":"^13.2.2","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^12.0.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.21","supertest":"^6.2.2","ts-node":"^10.4.0","typescript":"^4.5.5","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.1062.0","axios":"^0.25.0","class-transformer":"^0.5.1","class-validator":"^0.13.2","class-validator-jsonschema":"^3.1.0","dd-trace":"^1.7.0","decamelize":"^5.0.1","dotenv":"^14.3.0","express":"^4.17.2","express-jwt":"^6.1.0","hot-shots":"^9.0.0","ioredis":"^4.28.3","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.3.0","polly-js":"^1.8.3","qs":"^6.10.3","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.1.0","sequelize":"^4.44.4","serialize-error":"8.1.0","sqs-consumer":"^5.6.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.4.0"},"gitHead":"4d3c29b523608a3253da3b4eee5c2d22b8c56f31","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.19","_nodeVersion":"14.18.2","_npmVersion":"6.14.15","dist":{"integrity":"sha512-7I1j7bRmX6K+TIL+Pgu/e3q2Nqun+/P0+tGy3pqjZZSvIYLBphSG7MIH8hWrU5A9swl3P2KiwXxfBslStHTbMA==","shasum":"d2fc0bdddb5635d48c3b3436bb1999b13a2fc7cf","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.19.tgz","fileCount":195,"unpackedSize":795345,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh8S2jCRA9TVsSAnZWagAAEjMP/jlimZeqrhBTwXTXfbn4\n744g9FRlbIa4lg4ZZcwMPIxnXVzFQOY3fRNusrwVMfx2PREhWa1swq1KUmKh\nTYXMH/IJ+/Kf/hWmJzVmzNd+9Yl2qjQaTVhEkFGR9XL6hciHcau/6mH68ffb\nfafZbYNQHL8zZB0wfqX8xZHeb0F3v1CVVy7Yxd8dwynaSaa2Rh08odTka2Hi\nL9JCJHoQIPBcdCzx2fLbviPzgajkjLHPWMF8MmdMAjFpSLlaopffG4Dnbi+A\nAZ4jvMI1NT9h5dOvMtJ6CO18dEX4ivA7cfIMdZoPLw4rugkaxqXzv07LTr8V\nJRCiKeweS3vsbePAR8bE+T9DadcQZZIx4WD1z9m8HIJWd4IXwevJwBH3hv89\nn0iZYqbrFloHkWghYIKlRt8UO+rU89q3mwgmU4gxKpZ4CnLGR4VVCD8ATOoE\nY3GzyVUHxRPFZ9ddfROvYc9vtz4//oHeylNLudekvNUeS+FoYO+BdpT4i5Wo\nblB65c16zNuJHv2ZJOPQ+7chJ09PD32Nt+Yb648kVq2gTpSgunz0pGG+YEpr\n2iWyhEPXUOiLBov8WRo0pFBJxbdA6eZNHerAi83eIMYhtP346jJgXKfCGJLd\nYa0yF8us8005h2U+pzXScCl19clzeljwsOFynfIa3YMLS8Jx7jI6ug0jIlGO\nBgH4\r\n=IReC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCRd6EDWVpvAhb3OlSZQUMLFReQawpZWbI/S1Rg6OyXdwIgeDPw1/aWjl8eyw+pM5GsHPRkODCuZhaSES+J+QWP/fw="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.19_1643195811610_0.9082643394735481"},"_hasShrinkwrap":false},"9.11.20":{"name":"micro-kit-atlas","version":"9.11.20","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.2.1","@types/chai":"^4.3.0","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.13","@types/express-jwt":"^6.0.4","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.1","@types/ioredis":"^4.28.7","@types/js-yaml":"^4.0.5","@types/jsonwebtoken":"^8.5.8","@types/lodash":"^4.14.178","@types/mocha":"^9.1.0","@types/node":"^17.0.12","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.7","@types/request-promise-native":"^1.0.18","@types/sequelize":"^4.28.11","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.8","@types/sinon-chai":"^3.2.8","@types/supertest":"^2.0.11","@types/umzug":"^2.3.3","@types/uuid":"^8.3.4","@types/validator":"^13.7.1","@typescript-eslint/eslint-plugin":"^5.10.1","@typescript-eslint/parser":"^5.10.1","chai":"^4.3.5","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^8.7.0","eslint-plugin-import":"^2.25.3","eslint-plugin-mocha":"^10.0.3","eslint-plugin-prefer-arrow":"^1.2.3","eslint-plugin-promise":"^6.0.0","eslint-plugin-unicorn":"^40.1.0","mocha":"^9.2.0","nock":"^13.2.2","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^12.0.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.21","supertest":"^6.2.2","ts-node":"^10.4.0","typescript":"^4.5.5","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.1062.0","axios":"^0.25.0","class-transformer":"^0.5.1","class-validator":"^0.13.2","class-validator-jsonschema":"^3.1.0","dd-trace":"^1.7.0","decamelize":"^5.0.1","dotenv":"^14.3.0","express":"^4.17.2","express-jwt":"^6.1.0","hot-shots":"^9.0.0","ioredis":"^4.28.3","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.3.0","polly-js":"^1.8.3","qs":"^6.10.3","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.1.0","sequelize":"^4.44.4","serialize-error":"8.1.0","sqs-consumer":"^5.6.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.4.0"},"gitHead":"ae40821761d12ff999eb4b526ad133d313790ec0","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.20","_nodeVersion":"14.18.2","_npmVersion":"6.14.15","dist":{"integrity":"sha512-6phdzQjXsUaXZ09EjJU8gMeMhTv524yQklKmcyVefcUmI4zZMkAxkzpcJgVyJNx82ZkGzG5vsdYJo8gUUs17Wg==","shasum":"8a98803207ec5ee985907fa283e567e0c6d76df9","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.20.tgz","fileCount":195,"unpackedSize":795434,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJiA4VICRA9TVsSAnZWagAAyWYQAIeBwbVlzzDlIcq1mJXL\nrFYjxM4MI2yS/+99O92rhOrRJ4f8zuv5EvqmBYT40UcOMRlLPjBkO37WuzBw\nRmaHYXyCJiYN/pfWVZzxCnqyw+7xelQTMG2SmnYDgP20mgPnBUVkOaIv76XJ\nBijpVYjlGhV8M8Sxkj2a4gTdBAmfd//Cz9My5KOzTOWc68+jGrYu/ED3+RKc\n5Egb1cm35cHClEOvoZUD2YFSpAC/G+sz9LAK/8GyVDWB/dvtp5nMaAdnMASV\n1323hk14v3Y326E3N5gMwlyiSAseFZCKezGbg08RAeEveKZVWwFMmH5I/blW\nr+A82nlnuyYZDwo0f104YTb7m66RFmD81J1s7XIJwWTEUJ0BoSpgjmEXYTFW\nHZwVduRFsI0JlleQ3nHnGkZhMkkf/AGFfZU2RVjrw4j//B5/606zgev2ApfH\nQIAyiF2vBP0I65De/zioxsgN9+jAtEFz1xzN/TDA4PpNGgcid2kJR8t/P/1w\nMYuU1gnrJozlXjfNJjlEMTErs+xKyTYxumDoExoCdLqSygpRiTdASEnpIYe8\nlCEgE4WKHxroE3v3XtLykPvOD97VSBymV/EgxzYcin09r+iOaPb0E9bE2zMR\nDmPVI67OiJ+EYmTcMYCg9bNRmvlGtMROX0s6uvpVjQ7+b+rC32fYz/OUBJIa\nhvqt\r\n=acEY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCwHqbVgg3YV7HJVSjKgYT/jdDFU+nzf6DZ92yds7iFIAIgRURKTOX5NSFjCLehf9BtT53iTQs48s73ColLRhMyiLU="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.20_1644397895980_0.10445423335177328"},"_hasShrinkwrap":false},"9.11.20-alpha.1":{"name":"micro-kit-atlas","version":"9.11.20-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.2.1","@types/chai":"^4.3.0","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.13","@types/express-jwt":"^6.0.4","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.1","@types/ioredis":"^4.28.7","@types/js-yaml":"^4.0.5","@types/jsonwebtoken":"^8.5.8","@types/lodash":"^4.14.178","@types/mocha":"^9.1.0","@types/node":"^17.0.12","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.7","@types/request-promise-native":"^1.0.18","@types/sequelize":"^4.28.11","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.8","@types/sinon-chai":"^3.2.8","@types/supertest":"^2.0.11","@types/umzug":"^2.3.3","@types/uuid":"^8.3.4","@types/validator":"^13.7.1","@typescript-eslint/eslint-plugin":"^5.10.1","@typescript-eslint/parser":"^5.10.1","chai":"^4.3.5","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^8.7.0","eslint-plugin-import":"^2.25.3","eslint-plugin-mocha":"^10.0.3","eslint-plugin-prefer-arrow":"^1.2.3","eslint-plugin-promise":"^6.0.0","eslint-plugin-unicorn":"^40.1.0","mocha":"^9.2.0","nock":"^13.2.2","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^12.0.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.21","supertest":"^6.2.2","ts-node":"^10.4.0","typescript":"^4.5.5","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.1062.0","axios":"^0.25.0","class-transformer":"^0.5.1","class-validator":"^0.13.2","class-validator-jsonschema":"^3.1.0","dd-trace":"^1.7.0","decamelize":"^5.0.1","dotenv":"^14.3.0","express":"^4.17.2","express-jwt":"^6.1.0","hot-shots":"^9.0.0","ioredis":"^4.28.3","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.3.0","polly-js":"^1.8.3","qs":"^6.10.3","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.1.0","sequelize":"^4.44.4","serialize-error":"8.1.0","sqs-consumer":"^5.6.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.4.0"},"gitHead":"632dd5e7d2e57e118aee37de050677080c650865","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.20-alpha.1","_nodeVersion":"16.14.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-30wk0pNaLYWheSEA9WOcHvIZ5VRIYWsAiGsrmwANn9d1KGRLwLBxZeRqaPsIG9/ehVJ4BtjBo9RnEUr3SelPIg==","shasum":"32f19d500e91bd16ef1a9f2cde394d1a536db891","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.20-alpha.1.tgz","fileCount":199,"unpackedSize":801656,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiII+LACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoHhA//QlCAcy2rMq2sCrKN76AMjPsWKLFkSYBmatv95R3BPa3OoEep\r\nU6+ZPZA1N4+ZcjiTnXcJcUDIhXX/HIs0ivnVgLu8L8g4JfppSXzNHy1rTtzh\r\ngicBm6O4XkJjA7RrFMnohPAlbZpZyWLvP3/3KPKBZj198eVU42wxlQiKcHM7\r\nOWP/cezyhhqoBgz5Qz1gZYcvzwtVb/4H+Qav4gsE82DPTxikF+gtBAbwJ8YA\r\nX7DN1nIJqPlrhQj6JMTtYSeexQv6NyCiHdpBWS3+xsOSD5TaeNm1GJgHox0x\r\nHjfcxzlC0imaXcFn0ANXchbZaFGgQoDYLI231kln5jERT+vVOhNVxwI3+EPr\r\njgjOc8ckLeFgoeDGBmx2oRXxLkJNqx735cYztVz9zImrGjtJdmKlVFsCmIbH\r\nbvaxvEZ5jYJjQf90yFaVfBrLFB0ciOSDJZyu0VDV1GJrTDeqX/CuRYQEQF4W\r\neckXUkKcak7PHjw7F9DzWGowDSWi4sdWqof5VAtaTBrEugJqL5vQqJhARype\r\n1bywyRtPErqa3E6ltR327dHw9bLpkubtD8W30J9E31tv/hXdVDBy/fY8esrA\r\nOvKy7TJTJoaZqRPrGkohTCQ80HDYUa4XtjRpBObR7/804Di5nFjv001rrGUN\r\nA2v5XCVE+XfftChGDQyNtL46B7mdlbIqEIs=\r\n=k4BV\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEll8Rml7loW+7bmMdra36AJR5nTjLwtX8oD0gyatBX6AiA3TYn4a7USKkCF4fjIfEPsAvpufw318ZLQ6ngyfkokeQ=="}]},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.20-alpha.1_1646301067188_0.48825954299038177"},"_hasShrinkwrap":false},"8.2.2-alpha.4":{"name":"micro-kit-atlas","version":"8.2.2-alpha.4","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --compilers ts-node/register --require source-map-support/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"2.2.45","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"5.0.29","@types/express":"^4.17.11","@types/http-aws-es":"^1.1.2","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^12.20.4","@types/sequelize":"^4.0.80","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^5.2.0","nyc":"^13.1.0","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"5.0.7","sinon-chai":"3.3.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^4.1.0","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.2.4","aws-sdk":"^2.853.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^0.31.0","decamelize":"^1.2.0","dotenv":"^4.0.0","elasticsearch":"15.2.0","express":"^4.17.1","hot-shots":"^8.3.0","http-aws-es":"1.1.3","ioredis":"^3.2.2","lodash":"^4.17.21","micro-kit-aws-queue":"~3.1.5","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^2.1.0","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"a82ff28a3309f0f0bce61ebbaa72e3501a8df038","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    \n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n    \n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initService()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n    \n#### TODO? \nDescribe init(options) and finalize(app)?\n    \n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Support.\n  - Ajv validation (only for HTTP request parameters).\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n    \nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `host`\n_string_ _optional_\n\n**To be removed.**\n\n#### `serviceName`\n _string_ _optional_\n \n **To be removed.**\n\n#### `service_root_uri`\n_string_ _optional_\n\nThe URI segment that identifies the service, after the versioning and before route part.\n\n`/v1/service_root_uri/route`\n\nIf this parameter is not provided the routes will have empty segment.\n\n`/v1//route`\n\n#### `namespace`\n_string_ _optional_\n\n **To be removed.**\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted. \n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n    \nRouting\n------\nFor apps using Atlas, routing must be initialized between the `atlas.init(options)` and `atlas.finalize(app)`\n \n#### Basic use\nroutes.ts\n```typescript\n    import { router, Router } from 'micro-kit-atlas'\n    \n    export function init () {\n      router.exposed.GET('status', 1, async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n```\napp.ts\n```typescript    \n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    import * as routes from './routes'\n    \n    const options: Lib.Config = {\n      name: 'check_status',\n      service_root_uri: 'check_status',\n    }\n    \n    export async function initApp (): Promise<any> {\n      try {\n        const app = await init(options)\n        routes.init()\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initApp()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n    \nTo see the example in browser open `http://localhost:8080/v1/check_status/status`\n\n\nThe Router in Atlas has three interfaces, _ExposedRouter_, _ProtectedRouter_ and _InternalRouter_, available as `exposed`, `tokenProtected`, and `internal`. Both of them have the same static properties but with different signatures, the exposed router requires a version input while the internal defaults the version to `/internal/`. \n\n#### Exposed\n\n    static GET(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The express `request` is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\n#### Protected\n\n    static GET(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The ProtectedRequest (express `request`, extended with `req.tokenData`) is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\nProtected routes have a middleware check that the request has hit the API with req.tokenData attached. \nThe tokenData must contain the fields `globalid`, `uuid`, `client_id`, `scopes` and `grant_type` to make it past the middleware. A request without tokenData or without these fields will be met with a 401 Unauthorised response.\nAs a result, the controller gets a ProtectedRequest instead of a Request, so you can work with req.tokenData without worry.\n\nExample controller\n```typescript\nrouter.tokenProtected.GET('identities/me/is-dave', 1, exampleProtectedRequest, { schemaConfig: { params: '/IdentityUpdateGetParameters', validator: support.schema.validator }, })\n```\n```typescript\n\nexport async function exampleProtectedRequest (req: Router.ProtectedRequest, res: Router.ResponseHandler): Promise<boolean> {\n  const daves_uuid = '86d7e731-da23-4e2f-951e-81a04665f002'\n  const gid_uuid_in_token = req.tokenData.uuid // Router.ProtectedRequest says req has tokenData and tokenData is of type TokenData\n  return gid_uuid_in_token === daves_uuid\n}\n```\n\n#### Internal\n\n    static GET(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n\nExample:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\nExample with redirect response:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request, h: Router.ResponseHandler): Promise<Router.CustomResponse> => {\n        return h.redirect('https://globalid.net');\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\n\nSupport\n------\n#### Schema Validator for Routing\n\nAtlas offers json schema validation on the router with [Ajv](https://github.com/epoberezkin/ajv). \nHere is example how to implement uuid validation for a url parameter. First lets create the Ajv schema object:\n```typescript\n    // schemas.ts        \n    export const byUUID = {\n      $id: '/byUUID',\n      properties: {\n        uuid: {\n          $ref: '/UUID'\n        }\n      },\n      required: [\n        'uuid'\n      ]\n    }\n```   \nNext in app.ts we import all the defined schemas, in this case just `byUUID` and we load them to the Ajv validator at service startup:\n```typescript\n    import * as schemas from './schemas'\n    \n    // load all schemas\n    export const registerSchemas = async () => {\n      support.schema.addSchemasRecursive(schemas)\n    }\n    \n    ...\n    await registerSchemas()\n    await finalize(app)\n    ...\n````\nAfter that, on the router any route can validate uuid values that are on `req.body`, `req.query` or `req.param`. Here is route that expects uuid as url param:\n```typescript\n    import { router, Router, support } from 'micro-kit-atlas'\n    \n    const uuidSchemaConfig: Router.RequestValidation = {\n      validator: support.schema.validator, // Pass the Ajv validator\n      params: '/byUUID' // The $id of the schema\n    }\n    \n    export function init () {\n      router.exposed.GET('status/:uuid', 1, async (req: Router.Request) => {\n        return {id: req.params.uuid}\n      }, uuidSchemaConfig)\n    }\n    \n    export default {\n      init\n    }\n```\nCalling the route with invalid uuid will return error:\n    \n    http://localhost:8080/v1/check_status/get_uuid/123\n    {\"fields\":{\"missing\":[],\"uuid\":\"should match format \\\"uuid\\\"\"},\"error_id\":\"1adf7eae-c488-47b3-8c91-fb5942c60444\"}\n\nTo run the example:\n\n    cd examples\n    npm install\n    npm run support:schema\n    open http://localhost:8080/v1/check_status/get_uuid/with_bad_uuid\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client \nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n \n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html). \n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@8.2.2-alpha.4","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"integrity":"sha512-P2LFULOoe2ZZwgAusFUcZZfzuWNsUIldb4Ix4rmpdPClGe93num6VoWl+4Y8LeQmjIqnzshPoqAmGftPFU78yQ==","shasum":"ce0940db424031424ed279fa57ce6113a27ac80a","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.2.2-alpha.4.tgz","fileCount":63,"unpackedSize":146679,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDp2vYJ+xOnxg9FXJSvVZpaZFpmzpE8i+krqNGW+TxvpQIhAMvAYqHaPvZNVoIpikDvBrdeJKm+5pLPKkVGp2oOi1IS"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjPBFiACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrvqQ//WQppC3KkDj1P+k80dQsOWawWsYPX3WXIvAxMdsRl7g+KpCGn\r\nYjNXc0ZcP4dvrh+vgBLhzlk6WnzljQtfHxhmt8fjI60GdYOKfat7K2vw37EQ\r\nIH4bPVfIhvg29A2B+dK+uWPd+SdT8U+Xp2L+YIbfuinmShum1pLo/LDVMViC\r\nFrTk0D3bcYeGkxjBI7r0FswMT5z7VoX0aS55L8hEhL6RwMdv+oC8Lqc95fYU\r\nocoWb6O3YbcqgqS5RUr2Qr3pkgN5nbINDy7qyHqOQvAGD7ScAuTIhdoa4+f5\r\n2KDqWFaVsXb9cMKHOVt3ChlBkb7+FM6wPMjR62RoNMrswVZknAUUzlJbeSpj\r\nW9pq4jXg+mIcU3b5r1d1jgA7KwAckIIMpKVORlGZAcX+qlJzK8cDhKxCIFPr\r\nggUzWd/H0g8793WQCztu51jlnyATqfy2DaCXMJLcB2WGFtq7MbkkQ/68y8TX\r\n7xqr3vY2C7F1GP3RqGM6666wZABZbhW0T97DuX06teclDnabU46idvzNtEbE\r\nXw7++AreLUdFFQPxZDK4AT5hnpF6g/RFwFxphu24maQAzTIuv/tahOMlbHWH\r\n2n6e0q54pVUIzEnl/WkHmLv6WRQMUTjM65If/NzRhIV7zRfMzkEroHLxu7ZQ\r\nm1xR93tqPGOD7ho/avpcJOvzjupz+45ohhQ=\r\n=UCWM\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.2.2-alpha.4_1664880994018_0.9689088101235614"},"_hasShrinkwrap":false},"8.2.2-alpha.6":{"name":"micro-kit-atlas","version":"8.2.2-alpha.6","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --require ts-node/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --require ts-node/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"^5.2.7","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"^5.0.38","@types/express":"4.17.0","@types/express-serve-static-core":"4.16.7","@types/http-aws-es":"^6.0.1","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^14.17.8","@types/sequelize":"^4.28.10","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","dirty-chai":"^2.0.1","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^6.2.3","nyc":"^14.1.1","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"^7.5.0","sinon-chai":"^3.7.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^5.0.1","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.5.2","aws-sdk":"^2.960.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^1.2.1","decamelize":"^1.2.0","dotenv":"^10.0.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.5.0","http-aws-es":"^6.0.0","ioredis":"^4.27.7","lodash":"^4.17.21","micro-kit-aws-queue":"~3.2.0","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^8.1.0","winston":"^3.3.3","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"8777b06bbd88d44c8b9e9f13f4955cee82b37f68","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize, setKeepAliveTimeout } from 'micro-kit-atlas'\n    \n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n    \n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initService()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n    \n#### TODO? \nDescribe init(options) and finalize(app)?\n    \n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Support.\n  - Ajv validation (only for HTTP request parameters).\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n    \nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `host`\n_string_ _optional_\n\n**To be removed.**\n\n#### `serviceName`\n _string_ _optional_\n \n **To be removed.**\n\n#### `service_root_uri`\n_string_ _optional_\n\nThe URI segment that identifies the service, after the versioning and before route part.\n\n`/v1/service_root_uri/route`\n\nIf this parameter is not provided the routes will have empty segment.\n\n`/v1//route`\n\n#### `namespace`\n_string_ _optional_\n\n **To be removed.**\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted. \n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n    \nRouting\n------\nFor apps using Atlas, routing must be initialized between the `atlas.init(options)` and `atlas.finalize(app)`\n \n#### Basic use\nroutes.ts\n```typescript\n    import { router, Router } from 'micro-kit-atlas'\n    \n    export function init () {\n      router.exposed.GET('status', 1, async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n```\napp.ts\n```typescript    \n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    import * as routes from './routes'\n    \n    const options: Lib.Config = {\n      name: 'check_status',\n      service_root_uri: 'check_status',\n    }\n    \n    export async function initApp (): Promise<any> {\n      try {\n        const app = await init(options)\n        routes.init()\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initApp()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n    \nTo see the example in browser open `http://localhost:8080/v1/check_status/status`\n\n\nThe Router in Atlas has three interfaces, _ExposedRouter_, _ProtectedRouter_ and _InternalRouter_, available as `exposed`, `tokenProtected`, and `internal`. Both of them have the same static properties but with different signatures, the exposed router requires a version input while the internal defaults the version to `/internal/`. \n\n#### Exposed\n\n    static GET(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The express `request` is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\n#### Protected\n\n    static GET(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The ProtectedRequest (express `request`, extended with `req.tokenData`) is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\nProtected routes have a middleware check that the request has hit the API with req.tokenData attached. \nThe tokenData must contain the fields `globalid`, `uuid`, `client_id`, `scopes` and `grant_type` to make it past the middleware. A request without tokenData or without these fields will be met with a 401 Unauthorised response.\nAs a result, the controller gets a ProtectedRequest instead of a Request, so you can work with req.tokenData without worry.\n\nExample controller\n```typescript\nrouter.tokenProtected.GET('identities/me/is-dave', 1, exampleProtectedRequest, { schemaConfig: { params: '/IdentityUpdateGetParameters', validator: support.schema.validator }, })\n```\n```typescript\n\nexport async function exampleProtectedRequest (req: Router.ProtectedRequest, res: Router.ResponseHandler): Promise<boolean> {\n  const daves_uuid = '86d7e731-da23-4e2f-951e-81a04665f002'\n  const gid_uuid_in_token = req.tokenData.uuid // Router.ProtectedRequest says req has tokenData and tokenData is of type TokenData\n  return gid_uuid_in_token === daves_uuid\n}\n```\n\n#### Internal\n\n    static GET(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n\nExample:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\nExample with redirect response:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request, h: Router.ResponseHandler): Promise<Router.CustomResponse> => {\n        return h.redirect('https://globalid.net');\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\n\nSupport\n------\n#### Schema Validator for Routing\n\nAtlas offers json schema validation on the router with [Ajv](https://github.com/epoberezkin/ajv). \nHere is example how to implement uuid validation for a url parameter. First lets create the Ajv schema object:\n```typescript\n    // schemas.ts        \n    export const byUUID = {\n      $id: '/byUUID',\n      properties: {\n        uuid: {\n          $ref: '/UUID'\n        }\n      },\n      required: [\n        'uuid'\n      ]\n    }\n```   \nNext in app.ts we import all the defined schemas, in this case just `byUUID` and we load them to the Ajv validator at service startup:\n```typescript\n    import * as schemas from './schemas'\n    \n    // load all schemas\n    export const registerSchemas = async () => {\n      support.schema.addSchemasRecursive(schemas)\n    }\n    \n    ...\n    await registerSchemas()\n    await finalize(app)\n    ...\n````\nAfter that, on the router any route can validate uuid values that are on `req.body`, `req.query` or `req.param`. Here is route that expects uuid as url param:\n```typescript\n    import { router, Router, support } from 'micro-kit-atlas'\n    \n    const uuidSchemaConfig: Router.RequestValidation = {\n      validator: support.schema.validator, // Pass the Ajv validator\n      params: '/byUUID' // The $id of the schema\n    }\n    \n    export function init () {\n      router.exposed.GET('status/:uuid', 1, async (req: Router.Request) => {\n        return {id: req.params.uuid}\n      }, uuidSchemaConfig)\n    }\n    \n    export default {\n      init\n    }\n```\nCalling the route with invalid uuid will return error:\n    \n    http://localhost:8080/v1/check_status/get_uuid/123\n    {\"fields\":{\"missing\":[],\"uuid\":\"should match format \\\"uuid\\\"\"},\"error_id\":\"1adf7eae-c488-47b3-8c91-fb5942c60444\"}\n\nTo run the example:\n\n    cd examples\n    npm install\n    npm run support:schema\n    open http://localhost:8080/v1/check_status/get_uuid/with_bad_uuid\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client \nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n \n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html). \n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@8.2.2-alpha.6","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"integrity":"sha512-4ux6l4pDRa+X1HbM2TscCvbsH+Lcl97BmPeMT64pzqyou6/BHE07S+IHDjL04c3loirLulDDQZ+GnjaHWVq9lw==","shasum":"f431230aa5e797cc6a16594a36f75bedfac359d1","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.2.2-alpha.6.tgz","fileCount":63,"unpackedSize":145517,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDyBNtLiCx9reCUS0T350bUlJbbMgtyuD5KbzAEeek+zwIgf3vBV/Lg9QHG3FZUmUALMmWgLAu9dswNKj1Zpbf+0uA="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjPUX1ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoeHxAAj0cvFS0awUGIMvV0hgDjBHSbWcjgrxtK4vakOL1f2KyCoy4t\r\n/8Y5syeFvSH+XMAB5UH+ktcMk7Dvmotth3n5BEIAKtO+5H2KYVhHW2d1uMRz\r\ngifE9RgMMYwPyRSkbN4CH04QJuZ2XaZHUDtqP098mupyFQZMxsiHp+vX0SYJ\r\nL5ROawYJfn5bVYYgoEx0ypua/gj3SH8LZuyuLjsJsVCB0kGfZTjSP2TBkAf2\r\n/uYlppi99dXt0xc4gEQQLST4t6tj5YqCcsZQ7+GeTxlCoF6XMpePOAVqOnNM\r\nkVGha7wTo+BddkDRFWORzk70CrT95bo+dYhY7KGSXlOCJ+M9IrncCvpI7bq0\r\n3Xip0yT/p5RHIyTOyt19zAbnZ8Ux0nfpSFhyWDLzoXEqYxXFkygvtxb5YAUq\r\nhdQncnrLEWwb8RzICIEvldofDQ4LHtvct+quokYsMNXvW2OMbqZpTQJ9Sn7Y\r\nz+HFrlwSZoEUfg0TCFW/KrCiBBX9qgFkYM4uDb2q/jtcgISFxsu/Vyweg0E8\r\n34/LNrXmugI9s1PzJ02UpXdT7wSNVuW3BGzCKs7FD24zibSVeXF+ubHuIPc1\r\nX/IUOAH2SIJK9gyXPmgzVNV1WSKvhm/bT9/OfCNQon0Twl3HGBHAB4ANb26j\r\nWe2oLTjF+57KedPfmslFbK9zd8yPVBpBAf0=\r\n=ZD2S\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.2.2-alpha.6_1664959989652_0.9529050284724345"},"_hasShrinkwrap":false},"8.2.2-alpha.7":{"name":"micro-kit-atlas","version":"8.2.2-alpha.7","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --require ts-node/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --require ts-node/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"^5.2.7","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"^5.0.38","@types/express":"4.17.0","@types/express-serve-static-core":"4.16.7","@types/http-aws-es":"^6.0.1","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^14.17.8","@types/sequelize":"^4.28.10","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","dirty-chai":"^2.0.1","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^6.2.3","nyc":"^14.1.1","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"^7.5.0","sinon-chai":"^3.7.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^5.0.1","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.5.2","aws-sdk":"^2.960.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^1.2.1","decamelize":"^1.2.0","dotenv":"^10.0.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.5.0","http-aws-es":"^6.0.0","ioredis":"^4.27.7","lodash":"^4.17.21","micro-kit-aws-queue":"~3.2.0","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^8.1.0","winston":"^3.3.3","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"f9ca764ea29f606e845ac41a6a8fe49fc18ec184","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize, setKeepAliveTimeout } from 'micro-kit-atlas'\n    \n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n    \n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initService()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n    \n#### TODO? \nDescribe init(options) and finalize(app)?\n    \n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Support.\n  - Ajv validation (only for HTTP request parameters).\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n    \nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `host`\n_string_ _optional_\n\n**To be removed.**\n\n#### `serviceName`\n _string_ _optional_\n \n **To be removed.**\n\n#### `service_root_uri`\n_string_ _optional_\n\nThe URI segment that identifies the service, after the versioning and before route part.\n\n`/v1/service_root_uri/route`\n\nIf this parameter is not provided the routes will have empty segment.\n\n`/v1//route`\n\n#### `namespace`\n_string_ _optional_\n\n **To be removed.**\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted. \n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n    \nRouting\n------\nFor apps using Atlas, routing must be initialized between the `atlas.init(options)` and `atlas.finalize(app)`\n \n#### Basic use\nroutes.ts\n```typescript\n    import { router, Router } from 'micro-kit-atlas'\n    \n    export function init () {\n      router.exposed.GET('status', 1, async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n```\napp.ts\n```typescript    \n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    import * as routes from './routes'\n    \n    const options: Lib.Config = {\n      name: 'check_status',\n      service_root_uri: 'check_status',\n    }\n    \n    export async function initApp (): Promise<any> {\n      try {\n        const app = await init(options)\n        routes.init()\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initApp()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n    \nTo see the example in browser open `http://localhost:8080/v1/check_status/status`\n\n\nThe Router in Atlas has three interfaces, _ExposedRouter_, _ProtectedRouter_ and _InternalRouter_, available as `exposed`, `tokenProtected`, and `internal`. Both of them have the same static properties but with different signatures, the exposed router requires a version input while the internal defaults the version to `/internal/`. \n\n#### Exposed\n\n    static GET(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The express `request` is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\n#### Protected\n\n    static GET(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The ProtectedRequest (express `request`, extended with `req.tokenData`) is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\nProtected routes have a middleware check that the request has hit the API with req.tokenData attached. \nThe tokenData must contain the fields `globalid`, `uuid`, `client_id`, `scopes` and `grant_type` to make it past the middleware. A request without tokenData or without these fields will be met with a 401 Unauthorised response.\nAs a result, the controller gets a ProtectedRequest instead of a Request, so you can work with req.tokenData without worry.\n\nExample controller\n```typescript\nrouter.tokenProtected.GET('identities/me/is-dave', 1, exampleProtectedRequest, { schemaConfig: { params: '/IdentityUpdateGetParameters', validator: support.schema.validator }, })\n```\n```typescript\n\nexport async function exampleProtectedRequest (req: Router.ProtectedRequest, res: Router.ResponseHandler): Promise<boolean> {\n  const daves_uuid = '86d7e731-da23-4e2f-951e-81a04665f002'\n  const gid_uuid_in_token = req.tokenData.uuid // Router.ProtectedRequest says req has tokenData and tokenData is of type TokenData\n  return gid_uuid_in_token === daves_uuid\n}\n```\n\n#### Internal\n\n    static GET(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n\nExample:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\nExample with redirect response:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request, h: Router.ResponseHandler): Promise<Router.CustomResponse> => {\n        return h.redirect('https://globalid.net');\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\n\nSupport\n------\n#### Schema Validator for Routing\n\nAtlas offers json schema validation on the router with [Ajv](https://github.com/epoberezkin/ajv). \nHere is example how to implement uuid validation for a url parameter. First lets create the Ajv schema object:\n```typescript\n    // schemas.ts        \n    export const byUUID = {\n      $id: '/byUUID',\n      properties: {\n        uuid: {\n          $ref: '/UUID'\n        }\n      },\n      required: [\n        'uuid'\n      ]\n    }\n```   \nNext in app.ts we import all the defined schemas, in this case just `byUUID` and we load them to the Ajv validator at service startup:\n```typescript\n    import * as schemas from './schemas'\n    \n    // load all schemas\n    export const registerSchemas = async () => {\n      support.schema.addSchemasRecursive(schemas)\n    }\n    \n    ...\n    await registerSchemas()\n    await finalize(app)\n    ...\n````\nAfter that, on the router any route can validate uuid values that are on `req.body`, `req.query` or `req.param`. Here is route that expects uuid as url param:\n```typescript\n    import { router, Router, support } from 'micro-kit-atlas'\n    \n    const uuidSchemaConfig: Router.RequestValidation = {\n      validator: support.schema.validator, // Pass the Ajv validator\n      params: '/byUUID' // The $id of the schema\n    }\n    \n    export function init () {\n      router.exposed.GET('status/:uuid', 1, async (req: Router.Request) => {\n        return {id: req.params.uuid}\n      }, uuidSchemaConfig)\n    }\n    \n    export default {\n      init\n    }\n```\nCalling the route with invalid uuid will return error:\n    \n    http://localhost:8080/v1/check_status/get_uuid/123\n    {\"fields\":{\"missing\":[],\"uuid\":\"should match format \\\"uuid\\\"\"},\"error_id\":\"1adf7eae-c488-47b3-8c91-fb5942c60444\"}\n\nTo run the example:\n\n    cd examples\n    npm install\n    npm run support:schema\n    open http://localhost:8080/v1/check_status/get_uuid/with_bad_uuid\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client \nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n \n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html). \n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@8.2.2-alpha.7","_nodeVersion":"16.17.1","_npmVersion":"8.15.0","dist":{"integrity":"sha512-p3swNhZAE7gUWyrmlfkfDfb/MUa6+ZM9iWbIflqXk1v0KNqtLjZ1yf4RlAAvBwfiEJMNMMqYr35ZR22kQ+WV+w==","shasum":"0403e9329f073b8f5ea58f381140fe56d64cf8f6","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.2.2-alpha.7.tgz","fileCount":63,"unpackedSize":146078,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG4ztgrgZEFhFJeiTVojoCOOmL+LT90iuAwBuHIEKzVsAiAzEH57G6tCPJZmpZ+yByeZY3g4oe60pIs1acLPVEyltA=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjPqcxACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp0kBAAjJFUwcg1qGThDRmsZn4/QI/JIpq6LlRzRMcbgCD2NoXPCNid\r\nMDZyEnB6IeAIA0VM5I+OgHN2e7AYCYeqoW7poxDCJamDvJU5Bc4rEoc/RF8y\r\ntYqHTWzHAyrzkSkICn7TtW+8Hr9WFXy8wYyFzpIzpxhKyu3P9wuQ/z76VL/K\r\n/6AJ8/jZb3ZfHERNsdU68jsc6JGg7n4EeyTtwfl/2akQwTE0aRk8vmxVIzMX\r\nlDtXtEZKAEcT33s/txaXgpJQyMuZg3NaCI4IjpR7YM3EqECdRuv9OytBEgPC\r\nLMUBMs/+/qbf0hNmVeKemh38Ozly51OKW5IvapDub1EbCG/O4dKn5JgGpJq1\r\nPMQCqTQtOkwratRGD8iUGe/r9F5iAkCfgJQV1YTAGM2ziiwdnnZgA097mVgg\r\nzEIQdb66TU3lZ5tSSzqWAHGB9SGeVSBKxGAfm4HAq0XpFEJONKa8bZ049dCw\r\nXCHuuK46v3Pw6/s7/CVMdACwiyLq2RRy1oO9TfnPHNLUDK6ydYJ1qub3csTH\r\nbo6oo6/aGoySYPilxOzf+T1NEgw36e5yWyPdEHI/VuEyxWMaEcumksmzVIS5\r\n7O9PtCVJYwjBFYCI4C111STYkmCDje79vuYIEdEbRdlvIkWAMk0MIpBMraml\r\nM7+XOvdzw+ZufMH+/pF/ZKlWddw14VAtMmQ=\r\n=FKsb\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.2.2-alpha.7_1665050416975_0.3395844303454656"},"_hasShrinkwrap":false},"8.3.0":{"name":"micro-kit-atlas","version":"8.3.0","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --require ts-node/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --require ts-node/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"^5.2.7","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"^5.0.38","@types/express":"4.17.0","@types/express-serve-static-core":"4.16.7","@types/http-aws-es":"^6.0.1","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^14.17.8","@types/sequelize":"^4.28.10","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","dirty-chai":"^2.0.1","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^6.2.3","nyc":"^14.1.1","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"^7.5.0","sinon-chai":"^3.7.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^5.0.1","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.5.2","aws-sdk":"^2.960.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^1.2.1","decamelize":"^1.2.0","dotenv":"^10.0.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.5.0","http-aws-es":"^6.0.0","ioredis":"^4.27.7","lodash":"^4.17.21","micro-kit-aws-queue":"~3.2.0","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^8.1.0","winston":"^3.3.3","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"60d2fe939a411651e0f29582808945b7b3b1343e","_id":"micro-kit-atlas@8.3.0","_nodeVersion":"16.17.1","_npmVersion":"8.15.0","dist":{"integrity":"sha512-47xXlF8/dO6qzZp8MsjpfKYUGPPk08LNJynbnOmSl4YN0KIJSMzS0Oc02YO/EPZN3BQX+uA2RG9gwu4K6qG8hA==","shasum":"ee24d748a4ba11d24d67b089e101261e1ea88b6d","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.3.0.tgz","fileCount":63,"unpackedSize":145509,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICrcJYkE75ZNSsJYERe+0XaxYNlf5A6dv6coT1OkfaLjAiEAuLZc2yV2zUxSkAKGJ/GFqNK2KlgW3Uo7DDOJk9akDac="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjTmIaACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmquAA/+MFYi7sK6P9loqNGP204EvPmqO6IA88/vMUIWlu7A0AP0C1DG\r\noc4xD8kWpx+uM38DNRcrX/bqo/pwyJyCEF//eIV5l7UHge6iBwoBysEYK/tk\r\nduyDMptQL1qUqVhdW6B0EYGCURZRIDFcqTcYQo628v/EdnVPai9qUoU0x6eK\r\nYa1ZW4c3zZw/ntMD4b2L4sMOxvIBxos/ObHnJ+vaweD7VZ0rgZV+6PAVLCnv\r\nfcEMDub6Qstyzq4WhXRN8PoIzCwUBHAn9TRNdJFx5/BJwk77KwVp6cov1Cxx\r\nlcLUtKPPgD6KmDu818iAZjPJq0WzA1Hxnpybs8AXUGpyejzRAwndeYDNb0jr\r\nTjnCv5iIrTnac2EopU4ewbbFSiXkqWZSzfCyR7+AyYyZc4PNs7KmTa8IeIpR\r\nxxUE8UPAq/Hw7mqOuWpk4vcq7dRwMjS6Pm+Ii16LM2u7Yz3xygDPIPxrZ+hn\r\nflyeEj3XA7+j4yAoEiTVIJ13gvETZYcnt8+Fkz0X4b6nBXwFtVyoGvD0+TW5\r\nU7YuO0AEz0iGijk8eXJqZZY0hrc/axP7sKFYsp3SHuf8vgfitBe5BnbeFEHK\r\nl+WRNQtL0SxUDYJGaQadHn7bo/nbLoJlAEmcIj9H9VNWNUkg8mIPfecMAwMr\r\n8f9wHZWv2u91taCe2gtd60jASNXUWaNefSM=\r\n=lvbq\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.3.0_1666081306614_0.1624627475499658"},"_hasShrinkwrap":false},"9.11.21-alpha.3":{"name":"micro-kit-atlas","version":"9.11.21-alpha.3","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.2.1","@types/chai":"^4.3.0","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.13","@types/express-jwt":"^6.0.4","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.1","@types/ioredis":"^4.28.7","@types/js-yaml":"^4.0.5","@types/jsonwebtoken":"^8.5.8","@types/lodash":"^4.14.178","@types/mocha":"^9.1.0","@types/node":"^17.0.12","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.7","@types/request-promise-native":"^1.0.18","@types/sequelize":"^4.28.11","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.8","@types/sinon-chai":"^3.2.8","@types/supertest":"^2.0.11","@types/umzug":"^2.3.3","@types/uuid":"^8.3.4","@types/validator":"^13.7.1","@typescript-eslint/eslint-plugin":"^5.10.1","@typescript-eslint/parser":"^5.10.1","chai":"^4.3.5","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^8.7.0","eslint-plugin-import":"^2.25.3","eslint-plugin-mocha":"^10.0.3","eslint-plugin-prefer-arrow":"^1.2.3","eslint-plugin-promise":"^6.0.0","eslint-plugin-unicorn":"^40.1.0","mocha":"^9.2.0","nock":"^13.2.2","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^12.0.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.21","supertest":"^6.2.2","ts-node":"^10.4.0","typescript":"^4.5.5","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.1062.0","axios":"^0.25.0","class-transformer":"^0.5.1","class-validator":"^0.13.2","class-validator-jsonschema":"^3.1.0","dd-trace":"^1.7.0","decamelize":"^5.0.1","dotenv":"^14.3.0","express":"^4.17.2","express-jwt":"^6.1.0","hot-shots":"^9.0.0","ioredis":"^4.28.3","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.3.0","polly-js":"^1.8.3","qs":"^6.10.3","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.1.0","sequelize":"^4.44.4","serialize-error":"8.1.0","sqs-consumer":"^5.6.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.4.0"},"overrides":{"class-validator-jsonschema":{"class-transformer":">=0.5.1"},"routing-controllers":{"class-transformer":">=0.5.1","class-validator":"^0.13.2"}},"gitHead":"0d416a0f0a91e3cbdf64ff50d1ad39f268c9e561","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.21-alpha.3","_nodeVersion":"16.17.1","_npmVersion":"8.15.0","dist":{"integrity":"sha512-GF0u/YeqDmf7FN3z/M2TqTcEKqf8bLXzzVK6AhzrEhT0ZjRgIioF6wp7IvBcHzEsvVa22/rqSRxW1mC4YATH0Q==","shasum":"39361d324ff54deeebd64a6981a2637c1af2560e","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.21-alpha.3.tgz","fileCount":198,"unpackedSize":797420,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFsfYTmXsA1jasr0GgdqaZAqa8ekERj5VcAfhfxm92JpAiB3E0Nrv0GMATr8H0MI9/OBO38ZdhDyKYBSasAa8EGMhg=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjUUAMACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp5Vg/9EfqUe77ysHj3V++iC+5/DTR/VuaGgUH8VjMBsaFeAELdsKDD\r\nxG2od3/GVCjKUUdPbjPPCbE4tMT5l337Bwhu+n3lNJz/mqRBH8/G0Itc2DMQ\r\ncTYRAYOXbDdM3fCmNFZay0HmXKEReH6v+buNXiPFFxXIzlt1eKT3zbmI4kbC\r\nD+e0oxDTsl07j3rkWbGsTL9B8VcxIWJ5mXSOAcd4Q/IwO7Fo2h0mv2Hp40+5\r\nlBh8rwRu7K9sx4+I+95kjYqpGDFNkzdvCvfbEWShlz4bUqXHCe8OIh2FYH6M\r\nBIoSvKkT1N99ROQshmGxIq4U9gCH+npuZdazTPCyWTzPpXR4LfS/hyZQSPJG\r\nlkmbErHB56AX8qMAhJgSCROuZLeWWt1RTI+2OPeYrgzHKPkbuaOuHtzDHz72\r\npTRFVzjHqvYVm6up4XwqMbqa/YZ9S+M7ucEs+rVL36F4/v1TgwerlRS+Mih6\r\n3nlgruPKy/ABI/yUazQhMEyyX9hVZ01HgiiC/5d0PKcWiGhbJT4lAhqS5SIi\r\nlG1OX11FZOQZi3vIqEFyyn93ZSWKnLKVGCWRBcIfK5R/STeXTvHqVNgSSW68\r\nLI/APjJCfbrdCv3SrgG+nB1H1ev4Z51de3vZlwBEK74vD/s2r6pK3CeHL0i1\r\nnLjoZ2Q5bF3n8g7lBMAY6IuG9rm4Z7ydvvU=\r\n=BAxS\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.21-alpha.3_1666269196313_0.3279498604057247"},"_hasShrinkwrap":false},"9.11.21":{"name":"micro-kit-atlas","version":"9.11.21","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.2.1","@types/chai":"^4.3.0","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.13","@types/express-jwt":"^6.0.4","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.1","@types/ioredis":"^4.28.7","@types/js-yaml":"^4.0.5","@types/jsonwebtoken":"^8.5.8","@types/lodash":"^4.14.178","@types/mocha":"^9.1.0","@types/node":"^17.0.12","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.7","@types/request-promise-native":"^1.0.18","@types/sequelize":"^4.28.11","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.8","@types/sinon-chai":"^3.2.8","@types/supertest":"^2.0.11","@types/umzug":"^2.3.3","@types/uuid":"^8.3.4","@types/validator":"^13.7.1","@typescript-eslint/eslint-plugin":"^5.10.1","@typescript-eslint/parser":"^5.10.1","chai":"^4.3.5","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^8.7.0","eslint-plugin-import":"^2.25.3","eslint-plugin-mocha":"^10.0.3","eslint-plugin-prefer-arrow":"^1.2.3","eslint-plugin-promise":"^6.0.0","eslint-plugin-unicorn":"^40.1.0","mocha":"^9.2.0","nock":"^13.2.2","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^12.0.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.21","supertest":"^6.2.2","ts-node":"^10.4.0","typescript":"^4.5.5","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.1062.0","axios":"^0.25.0","class-transformer":"^0.5.1","class-validator":"^0.13.2","class-validator-jsonschema":"^3.1.0","dd-trace":"^1.7.0","decamelize":"^5.0.1","dotenv":"^14.3.0","express":"^4.17.2","express-jwt":"^6.1.0","hot-shots":"^9.0.0","ioredis":"^4.28.3","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.3.0","polly-js":"^1.8.3","qs":"^6.10.3","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.1.0","sequelize":"^4.44.4","serialize-error":"8.1.0","sqs-consumer":"^5.6.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.4.0"},"overrides":{"class-validator-jsonschema":{"class-transformer":">=0.5.1"},"routing-controllers":{"class-transformer":">=0.5.1","class-validator":"^0.13.2"}},"gitHead":"3f0e13896372fd6edcacb7e095e6cf4878a53267","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.21","_nodeVersion":"16.17.1","_npmVersion":"8.15.0","dist":{"integrity":"sha512-H3PeV1eJe+OsplUmQnArryFRSzbIPEaZLDT/nVrZkYg48N1EX5YDb0BGCOKBuJp77BxMRVz+OUByJnxc5V0cPg==","shasum":"0065cb5a66f3f5b80693fa6198c28a533475c28d","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.21.tgz","fileCount":198,"unpackedSize":797412,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFo4QjQY/umPAoAdNtc/bepv1QP42e4MmNzT8BZrub7eAiEA+DEZMHgHRaRdkRn0MyJX/vgUbPvOldJSPJybdzzOUdI="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjUULXACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqyLQ/9Eagw3bxr1sobT7oeiHDDJV15LjA+vTIQvcTFoATF2qLsfO/1\r\nsZ4ThcfecJ4bCve6MLlbcwIwNvI39AUzCAnBcwLX4OPUUwpNXSyfWCJ97YuJ\r\nptk9QZHRh6vrgw0zgmbv1xeKSN+6zDeEbNyJ0JdZ+Kwcx+85Cb0wXkbzggWF\r\nvlfR4MLIy2gmgk/x1hnGW7B9As0j2HLPwhf7GWsSQF/KhmkXit52dEvS37sD\r\nuIW47xu4dD4AjvfON0HXjBm1bTC8NHtJ+w8Yo04N6Pm38xctfoprXRLYC4Xq\r\nvV1y3+wzVE8y76uUJgUc59vsRuju+3tzRP0tUfBqLjxtOQD7c0vgKblNl5f6\r\nL3LiAaS8FZ0spf7vNqhbxgh0cTRQFUliwOVFVyuOYDFY+gzaCGL6x6Q14WkG\r\nB3QzeLB9YnBttBxY7g+ZMUvnCoBysw5B8hD6y8UEcQgZQ2w819SaKZCyvEoz\r\njvIA+5awTA4cNlKI8kwjmPK5Ywk07MRZuHq67PpZKcIbKgZxHiY3cZ2rKVjd\r\njG5pox3AiYopeXRmjBukYICpUuMLQS+hlpKIhImy+WLwHBgHLk1pd9dEXNuh\r\nJqrWq/OKz/T24bRW+dIOdNohSSzoOsL1Mp88vIm75jBtnkLMfvuYI4TOR/S0\r\n6V4kHxibX6GX+YO7IaZPfXuzj0+tjl7n19Y=\r\n=N+BK\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.21_1666269910960_0.3623858609717905"},"_hasShrinkwrap":false},"8.3.1-alpha.1":{"name":"micro-kit-atlas","version":"8.3.1-alpha.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --require ts-node/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --require ts-node/register --full-trace \"tests/**/*.integration.ts\" --exit","publish":"./pushversionask && npm run build && npm pack | xargs -i aws s3 cp {} s3://globalid-npm-repo/"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"^5.2.7","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"^5.0.38","@types/express":"4.17.0","@types/express-serve-static-core":"4.16.7","@types/http-aws-es":"^6.0.1","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^14.17.8","@types/sequelize":"^4.28.10","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","dirty-chai":"^2.0.1","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^6.2.3","nyc":"^14.1.1","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"^7.5.0","sinon-chai":"^3.7.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^5.0.1","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.5.2","aws-sdk":"^2.960.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^1.2.1","decamelize":"^1.2.0","dotenv":"^10.0.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.5.0","http-aws-es":"^6.0.0","ioredis":"^4.27.7","lodash":"^4.17.21","micro-kit-aws-queue":"~3.2.0","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^8.1.0","winston":"^3.3.3","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"2fc992d872e495f0fd34020bd9e415573be106d3","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize, setKeepAliveTimeout } from 'micro-kit-atlas'\n    \n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n    \n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initService()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n    \n#### TODO? \nDescribe init(options) and finalize(app)?\n    \n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Support.\n  - Ajv validation (only for HTTP request parameters).\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n    \nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `host`\n_string_ _optional_\n\n**To be removed.**\n\n#### `serviceName`\n _string_ _optional_\n \n **To be removed.**\n\n#### `service_root_uri`\n_string_ _optional_\n\nThe URI segment that identifies the service, after the versioning and before route part.\n\n`/v1/service_root_uri/route`\n\nIf this parameter is not provided the routes will have empty segment.\n\n`/v1//route`\n\n#### `namespace`\n_string_ _optional_\n\n **To be removed.**\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted. \n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n    \nRouting\n------\nFor apps using Atlas, routing must be initialized between the `atlas.init(options)` and `atlas.finalize(app)`\n \n#### Basic use\nroutes.ts\n```typescript\n    import { router, Router } from 'micro-kit-atlas'\n    \n    export function init () {\n      router.exposed.GET('status', 1, async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n```\napp.ts\n```typescript    \n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    import * as routes from './routes'\n    \n    const options: Lib.Config = {\n      name: 'check_status',\n      service_root_uri: 'check_status',\n    }\n    \n    export async function initApp (): Promise<any> {\n      try {\n        const app = await init(options)\n        routes.init()\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initApp()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n    \nTo see the example in browser open `http://localhost:8080/v1/check_status/status`\n\n\nThe Router in Atlas has three interfaces, _ExposedRouter_, _ProtectedRouter_ and _InternalRouter_, available as `exposed`, `tokenProtected`, and `internal`. Both of them have the same static properties but with different signatures, the exposed router requires a version input while the internal defaults the version to `/internal/`. \n\n#### Exposed\n\n    static GET(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The express `request` is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\n#### Protected\n\n    static GET(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The ProtectedRequest (express `request`, extended with `req.tokenData`) is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\nProtected routes have a middleware check that the request has hit the API with req.tokenData attached. \nThe tokenData must contain the fields `globalid`, `uuid`, `client_id`, `scopes` and `grant_type` to make it past the middleware. A request without tokenData or without these fields will be met with a 401 Unauthorised response.\nAs a result, the controller gets a ProtectedRequest instead of a Request, so you can work with req.tokenData without worry.\n\nExample controller\n```typescript\nrouter.tokenProtected.GET('identities/me/is-dave', 1, exampleProtectedRequest, { schemaConfig: { params: '/IdentityUpdateGetParameters', validator: support.schema.validator }, })\n```\n```typescript\n\nexport async function exampleProtectedRequest (req: Router.ProtectedRequest, res: Router.ResponseHandler): Promise<boolean> {\n  const daves_uuid = '86d7e731-da23-4e2f-951e-81a04665f002'\n  const gid_uuid_in_token = req.tokenData.uuid // Router.ProtectedRequest says req has tokenData and tokenData is of type TokenData\n  return gid_uuid_in_token === daves_uuid\n}\n```\n\n#### Internal\n\n    static GET(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n\nExample:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\nExample with redirect response:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request, h: Router.ResponseHandler): Promise<Router.CustomResponse> => {\n        return h.redirect('https://globalid.net');\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\n\nSupport\n------\n#### Schema Validator for Routing\n\nAtlas offers json schema validation on the router with [Ajv](https://github.com/epoberezkin/ajv). \nHere is example how to implement uuid validation for a url parameter. First lets create the Ajv schema object:\n```typescript\n    // schemas.ts        \n    export const byUUID = {\n      $id: '/byUUID',\n      properties: {\n        uuid: {\n          $ref: '/UUID'\n        }\n      },\n      required: [\n        'uuid'\n      ]\n    }\n```   \nNext in app.ts we import all the defined schemas, in this case just `byUUID` and we load them to the Ajv validator at service startup:\n```typescript\n    import * as schemas from './schemas'\n    \n    // load all schemas\n    export const registerSchemas = async () => {\n      support.schema.addSchemasRecursive(schemas)\n    }\n    \n    ...\n    await registerSchemas()\n    await finalize(app)\n    ...\n````\nAfter that, on the router any route can validate uuid values that are on `req.body`, `req.query` or `req.param`. Here is route that expects uuid as url param:\n```typescript\n    import { router, Router, support } from 'micro-kit-atlas'\n    \n    const uuidSchemaConfig: Router.RequestValidation = {\n      validator: support.schema.validator, // Pass the Ajv validator\n      params: '/byUUID' // The $id of the schema\n    }\n    \n    export function init () {\n      router.exposed.GET('status/:uuid', 1, async (req: Router.Request) => {\n        return {id: req.params.uuid}\n      }, uuidSchemaConfig)\n    }\n    \n    export default {\n      init\n    }\n```\nCalling the route with invalid uuid will return error:\n    \n    http://localhost:8080/v1/check_status/get_uuid/123\n    {\"fields\":{\"missing\":[],\"uuid\":\"should match format \\\"uuid\\\"\"},\"error_id\":\"1adf7eae-c488-47b3-8c91-fb5942c60444\"}\n\nTo run the example:\n\n    cd examples\n    npm install\n    npm run support:schema\n    open http://localhost:8080/v1/check_status/get_uuid/with_bad_uuid\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client \nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n \n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html). \n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@8.3.1-alpha.1","_nodeVersion":"16.18.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-2iFYJ6usdsqYYeFUYkruzAzHW7CRKcNPRd3R7V3k0QPB+dMScUuWj/XdzQsD+kwGguxNeyAi2pVCLp79GR25wA==","shasum":"222f56405abe43e1b4a6dbe534aa3d63ce0aac5b","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.3.1-alpha.1.tgz","fileCount":63,"unpackedSize":145685,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEdUrhY3HNC02ChySK1ofzHr2sGIpM8XpkMmswosouBOAiAL1QEQE0v/Sug3UExAV4U3P0bMxz6vFHhA6xYsqMu91A=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjatMjACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmriIw/9EQ/9WVR/5Uvk183gSDmraJbu+UjPVr0d5JlfsHlL/HHE1GrB\r\nrlAzPigZCeBJ64a3x6wd2MnA29AyZU+wWDv1W2WoMpOEh1QvMKOnrO9SXiVJ\r\ntOOBZhCyfDLwzrmwH55LyvJpmAzKu8j7me42wQX0UswgJMiYXY1RYm/6ZBGM\r\nbHMwSoOLqSjF+y60cJgX95nC0fer1wMVuQGlDMONVFzgdoqAwdwUDCA9+5DS\r\nl9xAXpSMrjwkpITJrVUsjru7XT34AAzxsh32AtV+3SNg+2svySS+pUyf7xRx\r\n79J6Wx0G148pUxwRe9mbE9N/I8s3fHhAmpmPeNaupJRjzkgl84nzv+I2c7yK\r\nmAaKOQogj+6a26tW9cH2ajyXdfpQIVFLMpiEKR7OfDRnp2JIktjs+6plZRwd\r\nbMoi2FTqFiWf15bSmaGpKmogmsL9gBoobb2vtYxJqE+PizBKJ6P6BWcDrTqd\r\ns3yob0mPNT+qpiewVM2DEurQP9AW3k6uwepLyaD8GmLi7hD6WBzwo90MUmn+\r\nqSM5fERLNqFgjzYuFnFPDPI/Q/R3RBU2pHKmMZL5niSs2MfUaL/QR8nsd9fQ\r\n7yS7gF/MAPOUTYHJGn5ly8wvdOtDhkqXW/FNQftnt2BT0HcO4G+4TippOAZT\r\n10ZxwWkgU+AWimNpA6d79FxWVJ0aL/uYuxQ=\r\n=LdOP\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.3.1-alpha.1_1667945251490_0.26243696087175605"},"_hasShrinkwrap":false},"8.3.1-alpha.2":{"name":"micro-kit-atlas","version":"8.3.1-alpha.2","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --require ts-node/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --require ts-node/register --full-trace \"tests/**/*.integration.ts\" --exit"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"^5.2.7","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"^5.0.38","@types/express":"4.17.0","@types/express-serve-static-core":"4.16.7","@types/http-aws-es":"^6.0.1","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^14.17.8","@types/sequelize":"^4.28.10","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","dirty-chai":"^2.0.1","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^6.2.3","nyc":"^14.1.1","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"^7.5.0","sinon-chai":"^3.7.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^5.0.1","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.5.2","aws-sdk":"^2.960.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^1.2.1","decamelize":"^1.2.0","dotenv":"^10.0.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.5.0","http-aws-es":"^6.0.0","ioredis":"^4.27.7","lodash":"^4.17.21","micro-kit-aws-queue":"~3.2.0","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^8.1.0","winston":"^3.3.3","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"d572776c473d6ea96b65b36ea06715ac02b3a421","readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize, setKeepAliveTimeout } from 'micro-kit-atlas'\n    \n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n    \n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initService()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n    \n#### TODO? \nDescribe init(options) and finalize(app)?\n    \n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - Exposed.\n- Storage.\n  - MySql.\n  - DynamoDB.\n  - ElasticSearch.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Support.\n  - Ajv validation (only for HTTP request parameters).\n- Utility.\n  - Custom logger.\n  - Data dog stats\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n    \nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `host`\n_string_ _optional_\n\n**To be removed.**\n\n#### `serviceName`\n _string_ _optional_\n \n **To be removed.**\n\n#### `service_root_uri`\n_string_ _optional_\n\nThe URI segment that identifies the service, after the versioning and before route part.\n\n`/v1/service_root_uri/route`\n\nIf this parameter is not provided the routes will have empty segment.\n\n`/v1//route`\n\n#### `namespace`\n_string_ _optional_\n\n **To be removed.**\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `dynamo`\n_boolean_ _optional_\n\nEnables DynamoDB client.\n\n#### `dynamo_config`\n_object_ _optional_\n\nConfiguration for DynamoDB.\n\n#### `elastic`\n_boolean_ _optional_\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\nEnables ElasticSearch client.\n\n#### `elastic_config`\n_object_ _optional_\n\nConfiguration options object for [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html) client. The configuration objects overrides any configuration passed via environment variables.\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted. \n- ElasticSearch\n  - ES_ENDPOINT - Optional, used for development and connecting to local ES server.\n  - ES_AWS_SECRET - Required only if ES_ENDPOINT is not provided.\n  - ES_LOGGING - Optional, used to enable logging. Auto enabled if ES_ENDPOINT is provided.\n- DynamoDB\n  - DYNAMO_ENDPOINT - Optional, used only for development and connecting to local DynamoDB server.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n\n    \nRouting\n------\nFor apps using Atlas, routing must be initialized between the `atlas.init(options)` and `atlas.finalize(app)`\n \n#### Basic use\nroutes.ts\n```typescript\n    import { router, Router } from 'micro-kit-atlas'\n    \n    export function init () {\n      router.exposed.GET('status', 1, async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n```\napp.ts\n```typescript    \n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, finalize } from 'micro-kit-atlas'\n    import * as routes from './routes'\n    \n    const options: Lib.Config = {\n      name: 'check_status',\n      service_root_uri: 'check_status',\n    }\n    \n    export async function initApp (): Promise<any> {\n      try {\n        const app = await init(options)\n        routes.init()\n        await finalize(app)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n    \n    initApp()\n```    \nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n    \nTo see the example in browser open `http://localhost:8080/v1/check_status/status`\n\n\nThe Router in Atlas has three interfaces, _ExposedRouter_, _ProtectedRouter_ and _InternalRouter_, available as `exposed`, `tokenProtected`, and `internal`. Both of them have the same static properties but with different signatures, the exposed router requires a version input while the internal defaults the version to `/internal/`. \n\n#### Exposed\n\n    static GET(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The express `request` is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\n#### Protected\n\n    static GET(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, version: number, handler: Router.ApiHandlerProtected, schemaConfig?: Router.RequestValidation): void\n    \n- `route` _required_ - The last segment of the URI path component. Shouldn't start with `/`.\n- `version` _required_ - Used for route versioning. The letter `v` is added before the number.\n- `handler` _required_ - Async handler callback function. The ProtectedRequest (express `request`, extended with `req.tokenData`) is available as first parameter, and extended response handler as second parameter. \n- `schemaConfig` _optional_ - Request validation object\n  - `validator` _required_ - The validator used, currently only Ajv is supported.\n  - `body` _optional_ - The id of the schema to validate the body parameters of the request  \n  - `query` _optional_ - The id of the schema to validate the query parameters of the request\n  - `param` _optional_ - The id of the schema to validate the url parameters of the request\n    \n        const schemaConfig = {\n            validator: support.schema.validator,\n            body: '/SendMoney',\n            param: '/UUID'\n        }\n\nProtected routes have a middleware check that the request has hit the API with req.tokenData attached. \nThe tokenData must contain the fields `globalid`, `uuid`, `client_id`, `scopes` and `grant_type` to make it past the middleware. A request without tokenData or without these fields will be met with a 401 Unauthorised response.\nAs a result, the controller gets a ProtectedRequest instead of a Request, so you can work with req.tokenData without worry.\n\nExample controller\n```typescript\nrouter.tokenProtected.GET('identities/me/is-dave', 1, exampleProtectedRequest, { schemaConfig: { params: '/IdentityUpdateGetParameters', validator: support.schema.validator }, })\n```\n```typescript\n\nexport async function exampleProtectedRequest (req: Router.ProtectedRequest, res: Router.ResponseHandler): Promise<boolean> {\n  const daves_uuid = '86d7e731-da23-4e2f-951e-81a04665f002'\n  const gid_uuid_in_token = req.tokenData.uuid // Router.ProtectedRequest says req has tokenData and tokenData is of type TokenData\n  return gid_uuid_in_token === daves_uuid\n}\n```\n\n#### Internal\n\n    static GET(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static POST(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static PUT(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n    static DELETE(route: string, handler: Router.ApiHandler, schemaConfig?: Router.RequestValidation): void\n\nExample:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request) => {\n        return 'Ok'\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\nExample with redirect response:\n```typescript    \n    // routes.ts\n    import { router, Router } from 'micro-kit-atlas'\n    export function init () {\n      router.internal.GET('status', async (req: Router.Request, h: Router.ResponseHandler): Promise<Router.CustomResponse> => {\n        return h.redirect('https://globalid.net');\n      })\n    }\n    \n    export default {\n      init\n    }\n    // open http://localhost:8080/internal/check_status/status\n```\n\nSupport\n------\n#### Schema Validator for Routing\n\nAtlas offers json schema validation on the router with [Ajv](https://github.com/epoberezkin/ajv). \nHere is example how to implement uuid validation for a url parameter. First lets create the Ajv schema object:\n```typescript\n    // schemas.ts        \n    export const byUUID = {\n      $id: '/byUUID',\n      properties: {\n        uuid: {\n          $ref: '/UUID'\n        }\n      },\n      required: [\n        'uuid'\n      ]\n    }\n```   \nNext in app.ts we import all the defined schemas, in this case just `byUUID` and we load them to the Ajv validator at service startup:\n```typescript\n    import * as schemas from './schemas'\n    \n    // load all schemas\n    export const registerSchemas = async () => {\n      support.schema.addSchemasRecursive(schemas)\n    }\n    \n    ...\n    await registerSchemas()\n    await finalize(app)\n    ...\n````\nAfter that, on the router any route can validate uuid values that are on `req.body`, `req.query` or `req.param`. Here is route that expects uuid as url param:\n```typescript\n    import { router, Router, support } from 'micro-kit-atlas'\n    \n    const uuidSchemaConfig: Router.RequestValidation = {\n      validator: support.schema.validator, // Pass the Ajv validator\n      params: '/byUUID' // The $id of the schema\n    }\n    \n    export function init () {\n      router.exposed.GET('status/:uuid', 1, async (req: Router.Request) => {\n        return {id: req.params.uuid}\n      }, uuidSchemaConfig)\n    }\n    \n    export default {\n      init\n    }\n```\nCalling the route with invalid uuid will return error:\n    \n    http://localhost:8080/v1/check_status/get_uuid/123\n    {\"fields\":{\"missing\":[],\"uuid\":\"should match format \\\"uuid\\\"\"},\"error_id\":\"1adf7eae-c488-47b3-8c91-fb5942c60444\"}\n\nTo run the example:\n\n    cd examples\n    npm install\n    npm run support:schema\n    open http://localhost:8080/v1/check_status/get_uuid/with_bad_uuid\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### DynamoDB\nTo use DynamoDB in your project you must enable it by passing `dynamo: true` to the Atlas configuration object.\n\n```typescript\n// to import the dynamo client\nimport { dynamo } from 'micro-kit-atlas'\n\n// to import the document client \nimport { dynamoDocumentClient } from 'micro-kit-atlas'\n```\n \n#### Configuration for development\n\nFor testing and local usage of DynamoDB, in the projects docker-compose file add:\n```yaml\ndynamodb:\n    restart: always\n    container_name: dynamodb\n    image: fitz/dynamodb-local\n    hostname: dynamo.dev.intranet\n    ports:\n    - \"8000:8000\"\n    command: fitz/dynamodb-local -sharedDb\n```\nand the service must depend on it:\n```yaml\ndepends_on:\n    - dynamodb\n```\nor download DynamoDB for local development from [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) and follow the instructions how to run it.\n\nWhen the local DynamoDB is running, it is exposed on `http://localhost:8000` so the `DYNAMO_ENDPOINT` environment variable must be set to this value.\n\n`AWS_REGION` is also required.\n\nTo access DynamoDB running locally, there is shell exposed on `http://localhost:8000/shell`, also can be accessed via AWS cli by passing the `--endpoint-url` parameter:\n\n`aws dynamodb command --endpoint-url http://localhost:8000`\n\n[Link](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html) for available commands for aws dynamo cli.\n\n#### Configuration for production\n\nFor running Atlas with DynamoDB in production `DYNAMO_ENDPOINT` must be undefined. AWS SDK must be initialized by either providing valid environment variables or the IAM role to be configured for the container where Atlas is running.\n\n\n#### Usage\nFor basic usage check the example in folder `examples\\storage\\dynamodb`. To run the example app:\n```bash\ncd examples\nnpm install\nnpm run storage:dynamodb\n```\n\nTo create a test table:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/create-table`\n\nTo list all the tables:\n\n`curl -X GET http://localhost:8080/v1/dynamodb/list-tables`\n\nTo put item into test table:\n`curl -X PUT http://localhost:8080/v1/dynamodb/test/item/:type` (replace :type with desired type)\n\nTo list all the items in test table:\n`curl -X GET http://localhost:8080/v1/dynamodb/test/items`\n\nFor advanced use check the official [documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html). \n\n### ElasticSearch\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\n\n### SNS/SQS\nTODO\n","readmeFilename":"readme.md","_id":"micro-kit-atlas@8.3.1-alpha.2","_nodeVersion":"16.18.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-I+4rstoWg/H86rHUHUF1eibg9ctFmKr0DmNqDyhKJJ8eWEY3AF4tipu5u0v5TqWA8c2PKV+1H7Wv6PC5wJWDZQ==","shasum":"30a21f6bc744e8e4aa359499530040b29447a9e4","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.3.1-alpha.2.tgz","fileCount":63,"unpackedSize":145573,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD4wJYQSIY4TySeddX242VEKQ/HAeCFHZpsAXhbeKK3ygIhAJsUvk2CkKe+A6T77psmkhBu4sMxCu+0mUUTxC4QDzAK"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjatiJACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmriAg/9Ex2zkWhXV7FjOLBPM68Cji5+BYpV1YgGLpgt5SuKwFDVbFvM\r\nvo9qv5KsAAZ+NJFCPFzoplzrGYlzNJQDTlKGg8BEX1HSCtCT/Hf5AuX1ImDw\r\nI3GoRhiYHMItC14FoTFxmh1FqaZrGF7sDvZLkVY4WZ/dMNInfemfkLPVk3Nk\r\nVyHonPRfwg/1/RHNV+UemzV/ZW4i4AwPn/Qy0oachWFYu4yit3U96pAC5CQv\r\nFAavXf6IjQdUBEprHTvAmJegTHBIOKFt0WwsAOAIm5/rSsTEu6WtIEGSNXc6\r\nICexzs6D4mAAPYEIA5APA8AtrwkDgx6TdOEuEWxNKLKIGynsb6HfvEMtay+Y\r\nixqIP7Fu8vLmbG4mN2uqKHxyGDwoAGHTL6pyT2uCb8IDxghkaTnFmhN5w6FL\r\nIBjb+xuV7rE+KVzulTW4pHDg7QwVbfZIuQ5sebqV3fGGLG81TNztPkVtXJFK\r\n3xCeUlmow6yuf0I/sPYPa/hqCbxdEt+DqnMQs1OeChWJqkc5gYfHIpQRceHD\r\nz5z6iRwSH3qkFLQtEH6Xz4KeJtH4g4x5NivYBmrp+dlVohR1aMGTPbduTD2D\r\nbLDYXPtwKi/odHvkLkivmx3b1TUKQAXWcvoK1YgUsW7+hZb3qABbgbJnGLi8\r\nTrkUTc6ZHWAHh21DdgbIOm1AeCQsgXHaf3Q=\r\n=CJN9\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.3.1-alpha.2_1667946633548_0.14735786492479086"},"_hasShrinkwrap":false},"8.3.1":{"name":"micro-kit-atlas","version":"8.3.1","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","author":{"name":"Nejc Horvat","email":"nejc@qloud.io"},"scripts":{"lint":"tslint \"src/**/*.ts\"","lint-fix":"tslint --fix \"src/**/*.ts\"","build":"npm run lint && npm run build:clean && npm run build:lib","build:clean":"rimraf dist","build:lib":"tsc --declaration","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:unit":"nyc --nycrc-path .nyrc_unit mocha --require ts-node/register --full-trace \"tests/**/*.unit.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration mocha --require ts-node/register --full-trace \"tests/**/*.integration.ts\" --exit"},"devDependencies":{"@types/chai":"4.0.10","@types/mocha":"^5.2.7","@types/sinon":"5.0.2","@types/sinon-chai":"3.2.1","@types/ajv":"^1.0.0","@types/body-parser":"^1.19.0","@types/elasticsearch":"^5.0.38","@types/express":"4.17.0","@types/express-serve-static-core":"4.16.7","@types/http-aws-es":"^6.0.1","@types/ioredis":"0.0.24","@types/knex":"0.0.56","@types/lodash":"^4.14.91","@types/node":"^14.17.8","@types/sequelize":"^4.28.10","@types/umzug":"^2.1.0","@types/supertest":"2.0.7","babel-cli":"6.24.1","babel-core":"6.25.0","babel-plugin-istanbul":"^4.1.4","babel-preset-es2015":"^6.24.1","chai":"4.1.0","dirty-chai":"^2.0.1","cross-env":"^5.0.1","eslint-plugin-typescript":"0.3.0","mocha":"^6.2.3","nyc":"^14.1.1","proxyquire":"^1.8.0","rimraf":"^2.7.1","sinon":"^7.5.0","sinon-chai":"^3.7.0","source-map-support":"^0.4.15","standard":"^10.0.2","supertest":"^3.3.0","ts-node":"^5.0.1","tslint":"^5.11.0","tslint-config-globalid":"^1.0.5","tslint-config-standard":"^7.0.0","typescript":"3.9.9","typescript-eslint-parser":"11.0.0"},"standard":{"parser":"typescript-eslint-parser","plugins":["typescript"],"globals":["sandbox","describe","context","before","beforeEach","after","afterEach","it","expect"]},"dependencies":{"ajv":"^5.5.2","aws-sdk":"^2.960.0","bluebird":"^3.7.2","body-parser":"^1.19.0","cls-hooked":"^4.2.2","dd-trace":"^1.2.1","decamelize":"^1.2.0","dotenv":"^10.0.0","elasticsearch":"^16.7.2","express":"^4.17.1","hot-shots":"^8.5.0","http-aws-es":"^6.0.0","ioredis":"^4.27.7","lodash":"^4.17.21","micro-kit-aws-queue":"~3.2.0","mysql2":"^2.2.5","opentracing":"^0.14.5","sequelize":"^4.44.4","serialize-error":"^8.1.0","winston":"^3.3.3","umzug":"^2.3.0","uuid":"^3.1.0"},"gitHead":"bceb457583b6a020957fbe6d0e444c8fbcff650e","_id":"micro-kit-atlas@8.3.1","_nodeVersion":"16.18.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-OnTKeknDB+x2Mc4pl4OLy8EtkCqxoJa0o2mTZuzsMJbOjrLh0yKIJsoIFGrrfF/29VOk2eRmoMwHdVQVLSmdbw==","shasum":"9b590ec05c018e7da8c01af5232f1e68ebe12bfb","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-8.3.1.tgz","fileCount":63,"unpackedSize":145565,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICQkWhSuU4ltC5YFMVG0eqs4P1gCAqDUPA/FdSXzUzYpAiA+y5i4109xoExnL7VGML4URt/BOZ8+wmfn0hR7ASnrtw=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJja3akACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpLFw/+NPA0JvWbgirzadqEYjBCUi5Ie4Z6rE+WZlMaJd5c7w4cYtc2\r\ntquHLk5d4DLFNipSTjVJt839FsxVmi8BKTInk3DwLYFv6XGNEIvRA5hB49IF\r\nXS0/FA5D4fTDOYmib5+0BzgRBaBCw9Aey7bNMgDunIYdL2SLgcIy6buEiP4/\r\nskC1pxIhreh/FNbl7XFpKfeb1FqGqNCS+kfImjO3wSqXrON6em29VMSbZE06\r\nl2Z+7V6DX4ghZpnhJXZ0TlqP+MvIdDAEbdqvUPLIodR35k4y2kwyvAT+D6O7\r\n0uy5qyD2fCUdh+v6kSWIrk2jSsn8o8pbKqaooxIKz5pwoGxs6LwJYDnV93sk\r\nqXC3fmNQZoUHBT2Qh4kYwvv5rE/BBXWQ02DCmsUYkkAGUEL1/7nAFGtT/zQS\r\ndurXgXqPqvOt1nLJpPaQQdBYH2xh6DJMg0XJoZXt7rjs3KJsuEmY5pjQOu+g\r\nnfAcUckdKvEeLcnSrfcJ8nbzY/GeZqB//iV1sskiJyr+wZg699/ZhBPn9D//\r\nHeUfGliaKf+l5chtRxFdIXfDOk3x63/InVhvXYQV05jonSd9kksBE11wRHQT\r\ni4BPCL6r9DJTgUEm78tIX0PLo2opLvMaz5yeImX/RPbqTCxpoKhFjvSmHLYe\r\n3NW02eRmhFjRPyK2qKhJtJUgnnqxDnqeL8g=\r\n=RQC4\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_8.3.1_1667987107867_0.5577363927200822"},"_hasShrinkwrap":false},"9.11.22":{"name":"micro-kit-atlas","version":"9.11.22","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.2.1","@types/chai":"^4.3.0","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.13","@types/express-jwt":"^6.0.4","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.1","@types/ioredis":"^4.28.7","@types/js-yaml":"^4.0.5","@types/jsonwebtoken":"^8.5.8","@types/lodash":"^4.14.178","@types/mocha":"^9.1.0","@types/node":"^17.0.12","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.7","@types/request-promise-native":"^1.0.18","@types/sequelize":"^4.28.11","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.8","@types/sinon-chai":"^3.2.8","@types/supertest":"^2.0.11","@types/umzug":"^2.3.3","@types/uuid":"^8.3.4","@types/validator":"^13.7.1","@typescript-eslint/eslint-plugin":"^5.10.1","@typescript-eslint/parser":"^5.10.1","chai":"^4.3.5","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^8.7.0","eslint-plugin-import":"^2.25.3","eslint-plugin-mocha":"^10.0.3","eslint-plugin-prefer-arrow":"^1.2.3","eslint-plugin-promise":"^6.0.0","eslint-plugin-unicorn":"^40.1.0","mocha":"^9.2.0","nock":"^13.2.2","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^12.0.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.21","supertest":"^6.2.2","ts-node":"^10.4.0","typescript":"^4.5.5","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.1062.0","axios":"^0.25.0","class-transformer":"^0.5.1","class-validator":"^0.13.2","class-validator-jsonschema":"^3.1.0","dd-trace":"^1.7.0","decamelize":"^5.0.1","dotenv":"^14.3.0","express":"^4.17.2","express-jwt":"^6.1.0","hot-shots":"^9.0.0","ioredis":"^4.28.3","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.3.0","polly-js":"^1.8.3","qs":"^6.10.3","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.1.0","sequelize":"^4.44.4","serialize-error":"8.1.0","sqs-consumer":"^5.6.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.4.0"},"overrides":{"class-validator-jsonschema":{"class-transformer":">=0.5.1"},"routing-controllers":{"class-transformer":">=0.5.1","class-validator":"^0.13.2"}},"gitHead":"3fd11b066734561a7d60fbb90a6acb5755f73fbe","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.22","_nodeVersion":"18.14.2","_npmVersion":"9.5.0","dist":{"integrity":"sha512-SKom5oOpdK+Kv2McY0BKEP3vI0LH2JYRT3OH4fP6OPMyaW7wkDOJ4vSZP84Yc/pOQd09OSvpUyWPZCOL2kTegw==","shasum":"beb180b4f36f2721cd437b10a48cb0916ab3d6e2","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.22.tgz","fileCount":198,"unpackedSize":797548,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA3jYArRtFyNdo7aq9MP/YY+eJkcDy6bJjorbPiONf18AiEApN68KW7zsQE8pjyIitCbgXJhBpq2yW5XFoIft39MMVI="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkDup0ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr/fA/+JGHlo7+HBakGdw8i53l/hNOIjUO+D1UGw/qMnHww7n68dBTm\r\n5rnmYDty6tBszO91HOzhovjvxPTpvV3MrkU4CjNvnQKQRf9VS3+SNP08EMVl\r\nvvRXkOZmVdFXGm0x6SyRD1uLykH/mKm5ny8/AVwEb06P4V9eX2scTXCP8B6h\r\nWxXHp1rtSvavx59WxN0nBDZcQ2OEp7oFNnjcH+XfhCRkuXOL3pg1SSyJTHii\r\n0rkc/epO7nPtmvOEYeYyyJtUsTcA4ii0hKOg024NDjgSZGmJCUso+r6s32Lc\r\nO+5Mhr6vtm6uiKquMEFAwK0mdyrKj9FhnikW2MgN/WGxkzTnx+5qWAHk94sB\r\nu3HBbHNouiaUo1XW1goLFCB+2Ik9+5eU6DoPEfEmSmokgZ7yDBeZTnP3/3GY\r\n2aFaTYqmzr+XvbXKL9yVQEzfmceS4mb4oE3lD/ao1L+4bB20zpcvcwyJ6p3C\r\nhf4hE2Lhx91tCor4xmefuoQ5AWJwPonuj85J4cSeSOWta9sbVcVmzh7gme9Y\r\n9IvC5Ns65H3yWbjnRJnY9p+ETzn2I00sMdzDvjiYKbmXTU12ANAWrycX+pU5\r\nAbOS4ucWVfLHzghVGaEOVKsCqr4P6UeGq2nf1N8z8DCoHeTIO9i7/AWUsR2J\r\n0qnUoxVx3NXoNie7fLzI3MAwM9r0VEoQ9ZQ=\r\n=RtrH\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.22_1678699123931_0.7321824849259555"},"_hasShrinkwrap":false},"9.11.23":{"name":"micro-kit-atlas","version":"9.11.23","description":"Base module for micro service","main":"dist/index.js","typings":"dist/index.d.ts","sideEffects":false,"author":{"name":"GlobaliD"},"repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"scripts":{"lint":"eslint \"src/**/*\" \"tests/**/*\" --format unix","lint-fast":"npm run lint -- -c .eslintrc-fast.js","lint-fix":"npm run lint -- --fix","build":"npm run build:clean && npm run build:lib && npm run build:types && npm run lint-fast","build:clean":"rimraf dist","build:types":"cpx \"types/**/*\" \"dist/types\"","copy-exposed-src":"cpx \"src/routing/exposed_service_generation_src/**/*\" \"dist/routing/exposed_service_generation_src\"","build:lib":"tsc --declaration -p tsconfig-build.json && npm run copy-exposed-src","test:full":"npm run build && npm run test","test":"npm run test:unit && npm run test:integration","test:cmd":"mocha --require ts-node/register","test:cmd-cov":"nyc --nycrc-path .nyrc_integration npm run test:cmd","test:cmd-fast":"mocha --require ts-node/register/transpile-only","test:unit":"nyc --nycrc-path .nyrc_unit npm run test:cmd -- \"tests/**/*.spec.ts\"","test:integration":"nyc --nycrc-path .nyrc_integration npm run test:cmd -- \"tests/**/*.integration.ts\"","test:nc:unit":"npm run test:cmd-fast -- \"tests/**/*.spec.ts\"","test:nc:integration":"npm run test:cmd-fast -- \"tests/**/*.integration.ts\""},"devDependencies":{"@globalid/eslint-plugin":"^1.2.1","@types/chai":"^4.3.0","@types/chai-as-promised":"^7.1.4","@types/dotenv":"^8.2.0","@types/express":"^4.17.13","@types/express-jwt":"^6.0.4","@types/get-port":"^4.2.0","@types/http-aws-es":"^6.0.1","@types/ioredis":"^4.28.7","@types/js-yaml":"^4.0.5","@types/jsonwebtoken":"^8.5.8","@types/lodash":"^4.14.178","@types/mocha":"^9.1.0","@types/node":"^17.0.12","@types/proxyquire":"^1.3.28","@types/qs":"^6.9.7","@types/request-promise-native":"^1.0.18","@types/sequelize":"^4.28.11","@types/serialize-error":"^4.0.1","@types/sinon":"^10.0.8","@types/sinon-chai":"^3.2.8","@types/supertest":"^2.0.11","@types/umzug":"^2.3.3","@types/uuid":"^8.3.4","@types/validator":"^13.7.1","@typescript-eslint/eslint-plugin":"^5.10.1","@typescript-eslint/parser":"^5.10.1","chai":"^4.3.5","chai-as-promised":"^7.1.1","chai-each":"0.0.1","chai-match-pattern":"^1.2.0","cpx":"^1.5.0","cross-env":"^7.0.3","dirty-chai":"^2.0.1","eslint":"^8.7.0","eslint-plugin-import":"^2.25.3","eslint-plugin-mocha":"^10.0.3","eslint-plugin-prefer-arrow":"^1.2.3","eslint-plugin-promise":"^6.0.0","eslint-plugin-unicorn":"^40.1.0","mocha":"^9.2.0","nock":"^13.2.2","nyc":"^15.1.0","proxyquire":"^2.1.3","rimraf":"^3.0.2","sinon":"^12.0.1","sinon-chai":"^3.7.0","source-map-support":"^0.5.21","supertest":"^6.2.2","ts-node":"^10.4.0","typescript":"^4.5.5","wait-for-expect":"^3.0.2"},"dependencies":{"aws-sdk":"^2.1062.0","axios":"^0.25.0","class-transformer":"^0.5.1","class-validator":"^0.13.2","class-validator-jsonschema":"^3.1.0","dd-trace":"^1.7.0","decamelize":"^5.0.1","dotenv":"^14.3.0","express":"^4.17.2","express-jwt":"^6.1.0","hot-shots":"^9.0.0","ioredis":"^4.28.3","js-yaml":"^4.1.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.21","micro-kit-aws-queue":"^3.3.0","polly-js":"^1.8.3","qs":"^6.10.3","request":"^2.88.2","routing-controllers":"^0.9.0","routing-controllers-openapi":"^3.1.0","sequelize":"^4.44.4","serialize-error":"8.1.0","sqs-consumer":"^5.6.0","umzug":"^2.3.0","uuid":"^8.3.2","winston":"^3.4.0"},"overrides":{"class-validator-jsonschema":{"class-transformer":">=0.5.1"},"routing-controllers":{"class-transformer":">=0.5.1","class-validator":"^0.13.2"}},"gitHead":"cf565cd2caa7e792e0334ce2d6706b1f05c4ed2d","bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"},"homepage":"https://gitlab.com/globalid/common/atlas#readme","_id":"micro-kit-atlas@9.11.23","_nodeVersion":"18.16.0","_npmVersion":"9.5.1","dist":{"integrity":"sha512-nPxlrYfjfjV2Rdss8EQlPfBt1gxXErrnHjgnpJth/YaTcSunPIi7lLWArxb/vDNIOOUyrrWA9am8fepVbdKE+Q==","shasum":"330b84416716f842f957f4105949dc96c5cfe754","tarball":"https://registry.npmjs.org/micro-kit-atlas/-/micro-kit-atlas-9.11.23.tgz","fileCount":198,"unpackedSize":797615,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCm+EZB4F34qXFRDxBN7JSDfZorWnO1GLCtbTD7joHdQQIhAIY+lE58QP3stqcm/TJhuEadjtLxoFwCm1FP3Z3P/QIz"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkSPQWACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrE8Q//dz2KrmqvnOeTuTptSLeM5fQ0xJ7ryqr0FuezFSF6KB37Tbd3\r\nfppGWnyfSIc/EuuOCykAe/ybp4iZjHCbSenjotNKfvF2DicMyF4DYWkYbUMG\r\n5+3bJaDppOgsTIFAYRjTMw0fvAHQDcU3AmMUL7cCWDuZNjr6zAwNOTuzIfaE\r\nMh+4hh3vSLa6vv9pM1fvs2gMdh1bKw/iUeXnxCgmmb9Afb/o2eUnrmnbP37v\r\nUTjEKRzSaYTeaOq5ZNkvMYXzwJ1C5MWGhJFm3TzOY5S4gFysIK0XMh2YtL0c\r\ntq4LKVB5CWeWVEcvCVvh7kae75lAdnhCNYRnshQy9/MUZXB2yI5UTfyUpZpA\r\nW84JOeXC8AVd19grR0bizhjpokqTVcX7i/0DD+QaQPljVEPC6zUNmSZmOmY0\r\n44oVnm4/Xw+fXhbqkc4OV68f630TUgetcLPf5Mt5xcJcXDD9dE9elk39k5Md\r\nlm0YGm6MmGBWVQpSb8NQotWbUUnekjSiyD5j8FbXTcaMki3C10u76CGOOlD1\r\n/ralOZy39l1I9Pu9VCPzj+TTl9lVXtA8PPRKW41mLPbDx3iDkIO8U1VvRc/2\r\nNdmh0kJEp+8vyn/0IcDV7PcM99cKNkY3usO1uP3TmthxSfrVedksIyDexaRn\r\n915r8d8guQIinuq8t1gzUUg7YCV+4qjibYI=\r\n=iy5T\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"directories":{},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"npm-gid","email":"npm@global.id"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-kit-atlas_9.11.23_1682502678453_0.745013111672586"},"_hasShrinkwrap":false}},"time":{"created":"2018-07-17T08:29:05.859Z","3.0.2":"2018-07-17T08:29:06.014Z","modified":"2023-04-26T09:51:18.793Z","3.0.3":"2018-07-17T10:07:41.717Z","3.0.4":"2018-07-17T12:40:14.616Z","3.0.5":"2018-07-17T16:00:36.008Z","3.0.6":"2018-08-20T10:11:42.504Z","3.0.7":"2018-09-03T10:55:53.652Z","3.0.8":"2018-09-05T07:00:43.917Z","3.0.9":"2018-09-11T06:51:50.371Z","3.1.0":"2018-09-12T12:04:53.304Z","3.1.1":"2018-09-14T12:03:46.560Z","3.1.2":"2018-10-03T08:50:21.555Z","3.1.3":"2018-10-03T10:47:20.589Z","3.1.5":"2018-10-05T14:45:45.330Z","3.2.0":"2018-10-10T15:52:48.481Z","3.2.1":"2018-10-11T09:36:01.424Z","3.2.2":"2018-10-11T09:47:44.174Z","4.0.0":"2018-10-11T16:59:04.839Z","4.0.1":"2018-10-12T07:45:21.259Z","4.0.2":"2018-10-12T09:15:09.978Z","4.0.3":"2018-10-19T15:06:21.172Z","4.1.0":"2018-10-24T09:46:19.929Z","4.1.1":"2018-10-24T14:26:42.622Z","4.1.2":"2018-10-24T14:48:07.409Z","5.0.0":"2018-10-25T14:00:18.957Z","5.0.1":"2018-10-29T13:11:49.866Z","5.1.0":"2018-10-30T08:51:10.481Z","5.1.1-0":"2018-10-30T12:34:33.335Z","5.1.2":"2018-11-08T16:03:53.152Z","5.2.0":"2018-11-21T08:28:06.613Z","5.2.1":"2018-11-22T15:31:22.183Z","5.2.2":"2018-11-23T13:23:10.965Z","5.2.3":"2018-11-26T09:43:25.140Z","6.0.0":"2018-11-30T08:45:41.759Z","6.0.1":"2018-12-07T11:27:42.817Z","6.1.0":"2018-12-07T14:50:47.239Z","3.0.59":"2018-12-07T18:34:31.403Z","6.2.0":"2018-12-10T15:22:34.896Z","6.2.1":"2018-12-20T13:17:51.849Z","6.3.0":"2019-01-07T09:44:08.966Z","7.0.0":"2019-01-08T08:44:45.207Z","7.1.0":"2019-01-08T09:52:47.547Z","7.2.0":"2019-01-14T15:07:39.451Z","7.2.1":"2019-01-31T12:22:14.816Z","8.0.0":"2019-02-01T11:36:50.626Z","8.1.0":"2019-02-06T08:53:42.550Z","8.1.1":"2019-02-06T16:21:27.384Z","8.1.2":"2019-02-07T10:52:57.954Z","8.1.3":"2019-02-28T14:00:53.572Z","8.1.4":"2019-06-27T08:53:36.138Z","8.1.5":"2019-06-27T12:51:14.346Z","9.0.0-alpha-1":"2019-08-01T09:20:18.914Z","9.0.0-alpha-2":"2019-08-02T07:02:27.891Z","9.0.0-alpha-3":"2019-08-02T08:04:42.403Z","9.0.0-alpha-4":"2019-08-06T08:00:17.634Z","9.0.0-alpha-5":"2019-08-06T14:59:23.803Z","9.0.0-alpha-6":"2019-08-06T15:22:29.094Z","9.0.0-alpha-7":"2019-08-07T07:07:34.132Z","9.0.0-alpha-8":"2019-08-07T07:15:10.291Z","9.0.0-alpha-9":"2019-08-07T13:52:18.107Z","9.0.0":"2019-08-08T13:14:58.324Z","9.0.1":"2019-08-08T15:35:17.254Z","9.1.0-alpha-1":"2019-08-22T08:57:49.335Z","9.1.0-alpha-3":"2019-08-22T12:39:45.805Z","9.1.0-alpha-5":"2019-08-22T14:24:35.771Z","9.1.0-alpha-6":"2019-08-23T14:37:08.896Z","9.1.0":"2019-08-27T13:46:10.793Z","9.1.1-alpha-1":"2019-08-30T07:18:46.359Z","9.1.1":"2019-08-30T07:48:31.620Z","9.2.0-alpha-2":"2019-09-09T07:31:40.261Z","9.1.2-alpha-2":"2019-09-11T12:38:17.221Z","9.2.0":"2019-09-13T12:09:32.685Z","9.2.1":"2019-09-16T07:12:43.956Z","9.2.2":"2019-09-16T08:57:32.706Z","9.2.3":"2019-09-16T15:06:33.424Z","9.2.4-alpha-1":"2019-09-19T11:32:26.433Z","9.2.4":"2019-09-20T08:51:01.246Z","9.2.5-alpha-1":"2019-09-24T08:25:36.308Z","9.2.5":"2019-09-25T12:31:43.335Z","9.2.6":"2019-09-29T11:20:13.161Z","9.2.7":"2019-10-02T08:36:21.004Z","9.2.8":"2019-10-07T07:09:23.952Z","9.2.9":"2019-10-09T14:57:22.631Z","9.2.10":"2019-10-16T07:58:11.445Z","9.3.0":"2019-10-21T07:07:47.135Z","9.4.0-alpha-1":"2019-10-21T13:54:22.884Z","9.4.0-alpha-2":"2019-10-21T18:38:40.359Z","9.4.0-alpha-3":"2019-10-21T19:02:26.640Z","9.4.0":"2019-10-25T08:57:44.097Z","9.4.1-alpha-1":"2019-10-27T16:29:08.287Z","9.4.1":"2019-10-30T12:26:24.069Z","9.5.0":"2019-11-18T14:53:52.276Z","9.5.1":"2019-11-19T13:32:58.304Z","9.5.2":"2019-11-19T14:26:58.908Z","9.5.3":"2019-11-19T14:57:39.792Z","9.5.4":"2019-11-20T16:33:36.241Z","9.6.0":"2019-11-26T15:51:52.201Z","9.6.1":"2019-11-28T21:07:49.347Z","9.6.2":"2019-11-29T08:17:43.550Z","9.6.3":"2019-12-05T14:00:38.463Z","9.6.4-alpha-2":"2019-12-09T11:26:14.354Z","9.6.4":"2019-12-10T13:53:43.224Z","9.6.5":"2019-12-19T07:52:46.423Z","9.6.6":"2020-01-24T14:23:00.512Z","9.6.7-alpha-1":"2020-02-05T16:08:40.156Z","9.6.7-alpha-3":"2020-02-07T11:00:42.257Z","9.6.7-alpha-4":"2020-02-07T14:01:51.149Z","9.6.7-alpha-5":"2020-02-10T10:48:41.914Z","8.1.6-alpha-1":"2020-02-11T16:14:29.907Z","9.6.7":"2020-02-24T12:20:50.909Z","8.1.6-alpha-2":"2020-02-25T13:02:48.588Z","8.1.6":"2020-02-25T14:10:34.744Z","9.6.8-alpha-1":"2020-02-26T10:07:14.641Z","8.1.7":"2020-02-27T08:31:22.616Z","8.1.8":"2020-02-27T08:58:27.982Z","9.6.8":"2020-02-27T09:01:02.748Z","9.6.9":"2020-02-28T10:46:36.331Z","9.6.10":"2020-03-03T08:46:53.621Z","8.1.9":"2020-03-03T10:43:54.842Z","9.7.1-alpha-2":"2020-03-03T11:17:21.386Z","9.7.1":"2020-03-03T14:08:53.223Z","9.7.2":"2020-03-16T07:37:01.179Z","9.7.3-alpha-1":"2020-03-16T10:16:51.444Z","9.7.3":"2020-03-16T11:05:36.910Z","9.7.4":"2020-03-17T09:36:13.355Z","9.7.5":"2020-03-27T11:48:05.967Z","9.7.6":"2020-03-31T10:39:19.219Z","9.7.7-alpha-1":"2020-04-07T11:53:22.145Z","9.7.7-alpha-2":"2020-04-17T09:21:00.092Z","9.7.7-alpha-3":"2020-04-20T16:23:50.946Z","9.7.7-alpha-4":"2020-04-20T16:59:39.901Z","9.7.7":"2020-05-04T21:09:17.236Z","9.7.8-alpha-1":"2020-05-05T18:46:10.992Z","9.7.8-alpha-2":"2020-05-05T19:15:43.139Z","9.7.8":"2020-05-06T14:03:56.129Z","9.7.9-alpha-1":"2020-05-11T18:35:54.219Z","9.7.9":"2020-05-11T20:48:03.166Z","9.7.10":"2020-05-15T10:50:36.628Z","9.7.11":"2020-05-19T08:14:04.494Z","9.7.12":"2020-06-02T05:07:26.769Z","9.7.13":"2020-06-10T07:33:43.905Z","9.7.14-alpha-1":"2020-06-10T11:50:32.007Z","9.7.14-alpha-2":"2020-06-11T08:23:24.490Z","9.7.14-alpha-3":"2020-06-11T13:26:22.178Z","9.7.14-alpha-4":"2020-06-11T14:15:19.083Z","9.7.14-alpha-5":"2020-06-15T12:36:33.106Z","9.7.14-alpha-6":"2020-06-15T14:24:00.207Z","9.7.14":"2020-06-16T09:00:14.052Z","9.7.15-alpha-1":"2020-06-19T12:17:10.490Z","9.7.15-alpha-2":"2020-06-22T11:43:33.911Z","9.8.0-alpha-1":"2020-06-24T07:45:15.081Z","9.8.0-alpha-3":"2020-06-24T13:13:50.914Z","9.8.0":"2020-06-24T13:49:53.030Z","9.8.1":"2020-07-15T06:55:39.263Z","9.8.2-alpha-1":"2020-07-22T09:56:02.621Z","9.8.2":"2020-07-28T13:40:46.924Z","9.8.3-alpha-1":"2020-08-05T13:49:36.670Z","9.8.3-alpha-2":"2020-08-11T13:02:02.873Z","9.8.3-alpha-3":"2020-08-12T09:38:39.026Z","9.8.3":"2020-08-13T06:49:19.001Z","9.8.4":"2020-08-21T07:40:25.944Z","9.9.0-alpha-1":"2020-08-21T07:50:22.802Z","9.9.0-alpha-2":"2020-08-25T09:02:05.894Z","9.9.0-alpha-3":"2020-08-25T10:33:40.724Z","9.8.5":"2020-08-25T13:28:31.850Z","9.9.0-alpha-5":"2020-08-26T06:35:52.980Z","9.8.6":"2020-08-26T06:48:20.992Z","9.9.0-alpha-6":"2020-08-26T07:49:54.640Z","9.8.7":"2020-08-27T15:06:05.192Z","9.9.0-alpha-7":"2020-09-01T07:43:47.229Z","9.9.0-alpha-8":"2020-09-01T12:53:01.712Z","9.9.0-alpha-9":"2020-09-04T07:05:01.241Z","9.8.8":"2020-09-04T07:18:34.555Z","9.9.0-alpha-10":"2020-09-04T11:47:23.784Z","9.8.9-alpha-1":"2020-09-08T08:20:24.552Z","9.8.9":"2020-09-08T08:27:23.560Z","9.8.10-alpha-1":"2020-09-08T10:12:27.448Z","9.8.10":"2020-09-09T07:35:44.327Z","9.9.0-alpha-11":"2020-09-09T10:19:24.668Z","9.9.0-alpha-12":"2020-09-09T15:50:38.669Z","9.9.0-alpha-13":"2020-09-10T19:54:50.494Z","9.9.0-alpha-14":"2020-09-11T13:57:14.840Z","9.9.0-alpha-15":"2020-09-12T06:18:16.449Z","9.9.0-alpha.16":"2020-09-14T14:16:28.763Z","9.9.1-alpha.1":"2020-09-16T11:21:03.909Z","9.9.1-alpha.2":"2020-09-16T15:54:22.686Z","9.9.1-alpha.3":"2020-09-18T10:45:45.343Z","9.9.1":"2020-09-22T05:24:14.911Z","9.9.2":"2020-09-29T08:58:25.466Z","9.9.3":"2020-09-30T09:37:46.110Z","9.9.4":"2020-10-01T21:24:05.273Z","9.9.5-alpha.1":"2020-10-06T07:11:03.745Z","9.9.5":"2020-10-06T09:06:48.684Z","9.9.6-alpha.1":"2020-10-06T09:13:02.067Z","9.9.6":"2020-10-06T10:32:25.754Z","9.9.7-alpha.1":"2020-10-08T08:46:15.707Z","9.9.7":"2020-10-08T12:40:39.843Z","9.9.8-alpha.1":"2020-10-09T08:17:15.035Z","9.9.8-alpha.2":"2020-10-14T21:30:25.238Z","9.9.8-alpha.3":"2020-10-15T09:43:14.705Z","9.9.8-alpha.4":"2020-10-19T08:07:51.369Z","9.9.8":"2020-10-19T13:29:47.315Z","9.9.9-alpha.2":"2020-10-22T11:55:59.454Z","9.9.9-alpha.3":"2020-10-23T07:30:27.784Z","9.9.9-alpha.4":"2020-10-26T08:28:48.929Z","9.9.9-alpha.5":"2020-10-26T09:25:51.934Z","9.9.9-alpha.6":"2020-10-26T12:37:44.417Z","9.9.9-alpha.7":"2020-10-26T14:31:41.431Z","9.9.9-alpha.8":"2020-10-27T12:44:31.954Z","9.9.9-alpha.9":"2020-10-29T09:12:56.509Z","9.9.9-alpha.10":"2020-10-29T10:15:54.159Z","9.9.9-alpha.11":"2020-10-29T12:47:16.274Z","9.9.9":"2020-10-30T07:13:33.980Z","9.9.10-alpha.1":"2020-11-02T09:27:17.365Z","9.9.10":"2020-11-06T08:50:36.893Z","9.9.11-alpha.1":"2020-11-10T11:38:45.695Z","9.9.11":"2020-11-11T07:50:03.643Z","9.9.12-alpha.1":"2020-11-11T13:28:38.417Z","9.9.12-alpha.2":"2020-11-13T08:44:19.843Z","9.9.12-alpha.3":"2020-11-13T10:48:33.644Z","9.9.12":"2020-11-13T12:13:18.284Z","9.9.13":"2020-11-14T21:14:15.545Z","9.9.14":"2020-11-15T17:46:40.513Z","9.9.15-alpha.1":"2020-11-16T15:08:00.046Z","9.9.15-alpha.3":"2020-11-16T18:43:01.925Z","9.9.15":"2020-11-17T11:18:01.668Z","9.9.16-alpha.1":"2020-11-19T13:22:32.661Z","9.9.16-alpha.2":"2020-11-19T15:42:34.750Z","9.9.16-alpha.3":"2020-11-23T17:34:04.963Z","9.9.16-alpha.4":"2020-11-23T18:25:30.729Z","9.9.16":"2020-11-25T08:07:43.950Z","9.9.17-alpha.1":"2020-11-26T14:14:52.023Z","9.9.17":"2020-11-27T09:27:54.870Z","9.9.18":"2020-12-02T08:53:10.037Z","9.9.19-alpha.1":"2020-12-10T10:46:18.418Z","9.9.19":"2020-12-10T15:06:04.793Z","9.9.20":"2020-12-16T20:50:03.386Z","9.9.21":"2020-12-21T20:37:37.854Z","9.9.22":"2020-12-23T10:33:54.493Z","9.9.23":"2020-12-29T10:26:13.915Z","9.9.24-alpha.1":"2021-01-04T10:27:09.480Z","9.9.24-alpha.2":"2021-01-04T11:39:04.276Z","9.9.24-alpha.3":"2021-01-06T09:47:17.602Z","9.9.24-alpha.4":"2021-01-06T10:06:02.963Z","9.9.24-alpha.5":"2021-01-06T15:15:57.435Z","9.9.24-alpha.6":"2021-01-07T07:55:57.967Z","9.9.24":"2021-01-11T12:33:12.399Z","9.9.25-alpha.1":"2021-01-18T12:21:32.181Z","9.9.25":"2021-01-18T16:36:16.464Z","9.9.26-alpha.1":"2021-02-01T08:27:50.132Z","9.9.26":"2021-02-01T09:46:06.912Z","9.9.27-alpha.1":"2021-02-11T17:31:01.309Z","9.9.27-alpha.2":"2021-02-12T17:13:33.871Z","9.9.27":"2021-02-15T14:53:36.175Z","9.9.28":"2021-02-19T09:25:46.716Z","9.10.0-alpha.1":"2021-02-23T10:57:30.329Z","9.9.29-alpha.1":"2021-02-23T11:07:50.891Z","9.10.0-alpha.2":"2021-02-24T14:14:48.637Z","9.10.0-alpha.3":"2021-02-24T16:47:25.966Z","9.9.29-alpha.2":"2021-02-25T10:23:47.825Z","9.9.29":"2021-02-25T12:13:21.450Z","9.10.0-alpha.4":"2021-02-25T13:08:21.915Z","9.9.30-alpha.2":"2021-02-26T13:35:00.905Z","9.9.30-alpha.3":"2021-03-01T08:39:35.255Z","9.9.30":"2021-03-01T10:10:55.298Z","8.1.10-alpha3":"2021-03-01T19:11:22.729Z","8.1.10-alpha5":"2021-03-01T19:44:25.392Z","8.1.10":"2021-03-01T20:17:25.691Z","9.9.31":"2021-03-08T21:29:46.547Z","9.10.0-alpha.5":"2021-03-11T14:03:52.757Z","9.10.0-alpha.6":"2021-03-11T15:16:32.321Z","9.10.1-alpha.1":"2021-03-16T08:46:49.959Z","9.10.0":"2021-03-16T10:06:08.984Z","9.10.1-alpha.2":"2021-03-16T10:06:32.730Z","9.10.1-alpha.3":"2021-03-16T12:44:19.958Z","9.10.1-alpha.4":"2021-03-17T12:47:38.922Z","9.10.1":"2021-03-19T11:54:50.661Z","9.10.2-alpha.1":"2021-03-22T13:46:14.627Z","9.10.2-alpha.3":"2021-03-23T12:26:07.719Z","9.10.2":"2021-03-23T13:26:10.916Z","9.10.3-alpha.1":"2021-04-02T13:37:52.157Z","9.10.3-alpha.2":"2021-04-07T06:47:35.208Z","9.10.3-alpha.3":"2021-04-07T11:16:19.521Z","9.10.3-alpha.4":"2021-04-07T13:19:59.629Z","9.10.3-alpha.5":"2021-04-08T09:10:29.696Z","9.10.3-alpha.6":"2021-04-09T06:41:20.225Z","9.10.3-alpha.7":"2021-04-09T06:42:16.193Z","9.10.3":"2021-04-09T12:51:44.580Z","9.11.4-alpha.1":"2021-04-12T07:52:42.159Z","9.11.4-alpha.2":"2021-04-12T10:52:27.681Z","9.11.0":"2021-04-14T09:51:22.772Z","9.11.1-alpha.1":"2021-04-20T07:15:49.306Z","9.11.1-alpha.2":"2021-04-20T12:03:44.256Z","9.11.1":"2021-04-21T11:12:54.316Z","9.11.2-alpha.1":"2021-04-26T10:31:49.081Z","9.11.2-alpha.2":"2021-04-26T13:21:06.150Z","9.11.2":"2021-04-26T15:34:24.217Z","9.11.3":"2021-05-07T09:25:38.949Z","9.11.4":"2021-05-11T11:48:50.229Z","8.1.11":"2021-05-19T09:15:32.979Z","9.11.5":"2021-05-19T09:16:17.834Z","9.11.6":"2021-05-26T08:57:35.955Z","9.12.0-alpha-3":"2021-06-08T14:03:46.830Z","9.11.7-alpha.1":"2021-06-16T10:39:21.723Z","9.11.7":"2021-06-18T10:47:16.885Z","9.11.8":"2021-06-30T08:29:19.602Z","9.11.9-alpha.1":"2021-07-09T09:05:17.631Z","9.11.9-alpha.2":"2021-07-09T12:02:29.320Z","9.11.9":"2021-07-12T08:57:20.161Z","8.2.0-alpha-1":"2021-08-05T12:02:58.783Z","8.2.0-alpha-2":"2021-08-05T13:28:44.107Z","8.2.0-alpha-3":"2021-08-05T14:49:09.104Z","8.2.0-alpha-4":"2021-08-06T08:01:09.499Z","8.2.0":"2021-08-11T14:16:00.262Z","9.11.10-alpha.1":"2021-08-17T15:06:20.513Z","9.11.10-alpha.2":"2021-08-18T13:52:31.223Z","9.11.10-alpha.3":"2021-08-19T09:14:05.821Z","8.2.1-alpha.1":"2021-08-26T08:28:56.643Z","8.2.1-alpha.2":"2021-08-26T14:11:59.684Z","8.2.1":"2021-08-27T15:14:18.396Z","9.11.10-alpha.5":"2021-09-07T07:48:58.002Z","9.11.11-alpha.1":"2021-09-07T13:22:18.173Z","9.11.11-alpha.2":"2021-09-13T07:58:35.136Z","9.11.10":"2021-09-14T12:17:56.863Z","9.11.11":"2021-10-12T09:29:15.173Z","9.11.12":"2021-10-13T13:39:10.214Z","9.11.13-alpha.1":"2021-11-05T08:21:58.935Z","9.11.13":"2021-11-05T10:38:50.270Z","9.11.14":"2021-11-25T13:38:20.290Z","9.11.15-alpha.1":"2021-11-30T17:24:02.059Z","9.11.15":"2021-12-01T14:47:01.931Z","9.11.16-alpha.1":"2021-12-16T16:13:38.953Z","9.11.16":"2021-12-17T11:38:54.471Z","9.11.17-alpha.1":"2021-12-30T14:57:04.282Z","9.11.17":"2022-01-03T10:43:34.687Z","9.11.18":"2022-01-26T08:43:46.945Z","9.11.19":"2022-01-26T11:16:51.774Z","9.11.20":"2022-02-09T09:11:36.208Z","9.11.20-alpha.1":"2022-03-03T09:51:07.366Z","8.2.2-alpha.4":"2022-10-04T10:56:34.213Z","8.2.2-alpha.6":"2022-10-05T08:53:09.850Z","8.2.2-alpha.7":"2022-10-06T10:00:17.226Z","8.3.0":"2022-10-18T08:21:46.862Z","9.11.21-alpha.3":"2022-10-20T12:33:16.716Z","9.11.21":"2022-10-20T12:45:11.165Z","8.3.1-alpha.1":"2022-11-08T22:07:31.706Z","8.3.1-alpha.2":"2022-11-08T22:30:33.800Z","8.3.1":"2022-11-09T09:45:08.063Z","9.11.22":"2023-03-13T09:18:44.176Z","9.11.23":"2023-04-26T09:51:18.669Z"},"maintainers":[{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"npm-gid","email":"npm@global.id"}],"description":"Base module for micro service","author":{"name":"GlobaliD"},"readme":"Atlas\n========\n\nAtlas is the core library used by the services inside the globaliD microservice architecture.\n\n- [**Upgrades**](UPGRADES.md)\n- [**Authentication / JWT & GBAC**](AUTH.md)\n\nBasic use:\n```typescript\n    process.env.AWS_REGION = 'local' // Required\n    import { Lib , init, setKeepAliveTimeout } from 'micro-kit-atlas'\n\n    const options: Lib.Config = {\n      name: 'veritas-service',\n    }\n\n    export async function initService (): Promise<any> {\n      try {\n        const app = await init(options)\n        const inst = await app.listen(8080, () => {\n          console.log('running on port:', 8080)\n        })\n        setKeepAliveTimeout(inst)\n\n        return inst\n      } catch (err) {\n        console.error('initService() error', err)\n        process.exit()\n      }\n    }\n\n    initService()\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run basic_use\n\n#### DD trace\nAltas initializes [dd trace](https://github.com/DataDog/dd-trace-js) by default. This can be turned off by setting env variable `DISABLE_DDTRACE=1`.\n\nIn order for dd trace to work properly, atlas should be the first import in project's entry file.\n\n#### TODO?\nDescribe init(options)?\n\n\nFeatures\n--------\n\n- Routing.\n  - Internal.\n  - TokenProtected (+ ScopeProtected, RoleProtected, GbacProtected)\n  - Exposed.\n- Storage.\n  - MySql.\n  - Redis.\n- Transport.\n  - SNS/SQS.\n- Utility.\n  - Custom logger.\n  - Data dog stats\n  - Obfuscator\n  - Lodash extensions\n\nInstallation\n------------\nInstall from npm:\n\n    npm install micro-kit-atlas\n\nConfiguration Options\n------------\nAtlas accepts the following properties in the options object:\n\n#### `name`\n_string_ _required_\n\nName of the service.\n\n#### `version`\n_string_ _optional_\n\nVersion of the service.\n\n#### `routing`\n_object_ _optional_\n\nConfiguration options object for [routing](https://github.com/typestack/routing-controllers). See `Routing.Config`.\n\n#### `redis`\n_boolean_ _optional_\n\nEnables Redis client.\n\n#### `redis_config`\n_object_ _optional_\n\nConfiguration options object for [ioredis](https://github.com/luin/ioredis/blob/master/API.md) client.\n\n#### `database`\n_boolean_ _optional_\n\nEnables MySql.\n\n#### `database_config`\n_object_ _optional_\n\nConfiguration options object for [Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor) client.\n\n#### `obfuscator`\n_boolean_ _optional_\n\nEnables obfuscator\n\n#### `stats`\n_boolean_ _optional_\n\n#### `transport`\n_boolean_ _optional_\n\n### Routing configuration\n\n`Routing.Config` object accepts the following properties:\n\n#### `controllers`\n_Function[]_ _required_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) controller classes.\n\n#### `jwtOptions`\n_ojbect_ _optional_\n\n```typescript\n{\n  secret: string | Buffer | SecretCallback | SecretCallbackLong\n  issuer: string | string[] | false\n\n  algorithms?: string[] // defaults to ['RS256', 'HS256']\n  audience?: string | string[]\n  // + other options\n}\n\n```\n\nOptions are passed to [express-jwt](https://github.com/auth0/express-jwt#additional-options).\n\nFor services without protected API routes, JWT auth can be disabled. This is done by setting JWT_AUTH_DISABLED env variable to \"1\" and not passing the `jwtOptions` to config.\n\n#### `middlewares`\n_Function[]_ _optional_\n\nList of [routing-controllers](https://github.com/typestack/routing-controllers) middleware classes.\n\n#### `optionsOverwrites`\n_RoutingControllersOptions_ _optional_\n\n[routing-controllers](https://github.com/typestack/routing-controllers) options to overwrite default atlas configuration.\n\n\n### Environment Variables\n- Globals\n  - AWS_REGION - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_ACCESS_KEY_ID - Required. AWS region must be provided so Atlas can initialize.\n  - AWS_SECRET_ACCESS_KEY - Required. AWS region must be provided so Atlas can initialize.\n  - NAMESPACE - Optional, required for SNS/SQS to be namespaced.\n  - NODE_ENV - Optional, used for logger to determine if it should insert white space into the output. If `production` no white space will be inserted.\n- Routing\n  - DISABLE_RESPONSE_VALIDATION - Optional. Disables API response validation if set to true or 1.\n- Database (MySql)\n  - DATABASE_CONNECTION_URL - Required. Database connection string.\n  - DATABASE_LOGGING - Optional. Enables or disables logging. Accepts both true or 1.\n  - DATABASE_HOST - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PORT - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_USERNAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_PASSWORD - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n  - DATABASE_NAME - Optional. Overrides the DATABASE_CONNECTION_URL if provided.\n- Redis\n  - REDIS_HOST - Optional. Overrides the default host `127.0.0.1`.\n  - REDIS_PORT - Optional. Overrides the default port `6379`.\n- Obfuscator\n  - OBFUSCATOR_SALT_ID - Required.\n  - OBFUSCATOR_SALT_PART - Required.\n  - OBFUSCATOR_ENDPOINT - Required.\n  - OBFUSCATOR_RETRY_COUNT - Optional. Overrides the default `3`.\n  - OBFUSCATOR_RETRY_TIMEOUT_MS - Optional. Overrides the default `1000`.\n\n\nRouting\n------\nFor apps using Atlas, routing is defined with list of controller classes in `atlas.init(options)`. Controller classes must be decorated with one of the controller decorators `Controller`, `JsonController` or `RestController`. First two are defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. `RestController` is defined in atlas on top of `JsonController` to ease implementing REST API. Param and response classes should be defined using [routing-controllers](https://github.com/typestack/routing-controllers) as described on [routing-controllers page](https://github.com/typestack/routing-controllers). Atlas defined some extra validation decorators described in the `Extra validation decorators` section.\n\n### Basic use\ncontroller.ts\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas/routing'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status')\n      async getStatus(): Promise<string> {\n        return 'Ok'\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstController } from './controller'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: [FirstController]\n      }\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\nTo run the example:\n\n    cd examples\n    npm install\n    npm run routing:basic_use\n\nTo see the example in browser open `http://localhost:8080/v1/status`\n\n\nThe Router in Atlas has three decorator namespaces `Exposed`, `TokenProtected`, `RoleProtected`, `ScopeProtected`, `GbacProtected`, and `Internal`. All of them have the same set of decorators with different params type. The exposed and token protected decorators requires a version property while the internal doesn't. Generated routes have different format. The exposed and token protected decorators start with configured version (eg. `/v1/route`) while internal start with `/internal/`.\n\n#### Exposed Decorators\n\n```typescript\nGET: (route: string, params?: ExposedRouteParams): MethodDecorator\nPOST: (route: string, params?: ExposedRouteParams): MethodDecorator\nPUT: (route: string, params?: ExposedRouteParams): MethodDecorator\nDELETE: (route: string, params?: ExposedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `ExposedRouteParams`.\n\nExample controller\n```typescript\n    import { JsonController, Exposed } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @Exposed.GET('status', { version: 2 })\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/v2/status`\n\n#### TokenProtected Decorators\n\n```typescript\nGET: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: TokenProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `TokenProtectedRouteParams`.\n\nProtected routes run a middleware which verifies and parses a JWT access token ([configuration](#routing-configuration)). Unauthorised request will be met with a 401 Unauthorised response. Use `@TokenDataParam() tokenData: TokenData` parameter to access parsed claims.\nFor optional authentication use `@TokenDataParam(false) tokenData?: TokenData` with Exposed route decorator.\n\nExample controller\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid')\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<TokenData> {\n        return tokenData\n      }\n    }\n```\n\nExample controller with [additional claim requirements](#tokenprotectedrouteparams)\n```typescript\n    import { JsonController, TokenProtected, TokenDataParam, TokenData } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController () {\n      @TokenProtected.GET('my-uuid', {\n        entityType: TokenEntityType.CLIENT,\n        scopes: ['idenity.read', 'identity.manage'],\n        roles: ['admin'],\n        claims: {\n          extraClaim: true,\n          andAnother: 'yup',\n        }\n      })\n      async getMyUuid(@TokenDataParam() tokenData: TokenData): Promise<ToknData> {\n        return tokenData\n      }\n    }\n```\n\n#### GbacProtected Decorators\n\n```typescript\nGbacProtected(allowedPermissions?: string | string[])\n```\n\n`GbacProtected` decorator is intended to be used with GBAC permissions. The handler needs to be linked to a group. It takes one optional parameter. The execution of the handler is always allowed when the caller is the owner of the group. If the caller is not the owner of the group the execution will be allowed only when the called has one of the permissions required. A special permissions is defined 'GROUP_MEMBER' as `GROUP_MEMBER_ROLE` constant.\n\n```typescript\nGET: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPOST: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nPUT: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\nDELETE: (route: string, params?: GbacProtectedRouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `GbacProtectedRouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @GbacProtected('ger-perm').GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### Internal Decorators\n\n```typescript\nGET: (route: string, params?: RouteParams): MethodDecorator\nPOST: (route: string, params?: RouteParams): MethodDecorator\nPUT: (route: string, params?: RouteParams): MethodDecorator\nDELETE: (route: string, params?: RouteParams): MethodDecorator\n```\n\n- `route` _required_ - The last segment of the URI path component.\n- `params` _optional_ - See `RouteParams`.\n\nExample:\n```typescript\n    import { JsonController, Internal } from 'micro-kit-atlas'\n\n    @JsonController()\n    export class FirstController {\n      @Internal.GET('status')\n      async getStatus(): Promise<string> {\n        return 'ok'\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n### REST Controllers\n\nREST routing can be defined using `RestController` class decorator and `Exposed.Rest`, `TokenProtected.Rest` and `Internal.Rest` set of method decorators.\n\n#### RestController decorator\n\n`RestController` decorator is an extension of `JsonController` defined in [routing-controllers](https://github.com/typestack/routing-controllers) library. It takes two parameters:\n\nExample:\n```typescript\n    import { RestController, Internal, Body, Params, OrUndefined } from 'micro-kit-atlas'\n    import { IsString, IsUUID, IsInstance, IsEmail, IsUrl, MinLength } from 'micro-kit-atlas/routing'\n\n    class AddUserBody {\n      @IsString() @MinLength(2) name!: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() contact_email!: string\n    }\n\n    class ModifyUserBody {\n      @IsString() @MinLength(2) @OrUndefined() name?: string\n      @IsString() @IsUrl() @OrUndefined() picture?: string\n      @IsString() @IsEmail() @OrUndefined() contact_email?: string\n    }\n\n    class User extends AddUserBody {\n      @IsUUID('4') uuid!: string\n    }\n\n    class Users {\n      @IsInstance(User, { each: true })\n      users!: User[]\n    }\n\n    class UserIdParams {\n      @IsUUID('4') user_uuid!: string\n    }\n\n    @RestController('user', 'user_id')\n    export class FirstController {\n      @Internal.Rest.create({\n        description: `Create a new user`,\n        response: User,\n        responseDescription: `New user was created`,\n        errors: [UserWithEmailAlreadyExistsError],\n      })\n      async createUser(@Body() body: AddUserBody): Promise<User> {\n        if (userWithEmailExists(body.contact_email)) {\n          throw new UserWithEmailAlreadyExistsError()\n        }\n        return addUserToDb(body)\n      }\n\n      @Internal.Rest.getOne({\n        description: `Get a user by id`,\n        response: User,\n        responseDescription: `Return a single user`,\n        errors: [UserMissingError],\n      })\n      async getUser(@Params() params: UserIdParams): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return getUserFromDb(params.user_uuid)\n      }\n\n      @Internal.Rest.getList({\n        description: `Get all users`,\n        response: User,\n        responseDescription: `Return a list of users`,\n      })\n      async getUsers(): Promise<Users> {\n        return getUsersFromDb()\n      }\n\n      @Internal.Rest.update({\n        description: `Modify a user`,\n        response: User,\n        responseDescription: `User was updated`,\n        errors: [UserMissingError],\n      })\n      async updateUser(@Params() params: UserIdParams, @Body() body: ModifyUserBody): Promise<User> {\n        if (userMissing(params.user_uuid)) {\n          throw new UserMissingError()\n        }\n        return updateUserInDb(params.user_uuid, body)\n      }\n\n      @Internal.Rest.remove({\n        description: `Remove a user by id`,\n        responseDescription: `User was deleted`,\n      })\n      async removeUser(@Params() params: UserIdParams): Promise<void> {\n        return removeUserFromDb(params.user_uuid)\n      }\n    }\n```\nTo see the example in browser open `http://localhost:8080/internal/status`\n\n#### `controllerNamespace`\n_String_ _required_\n\nNamespace of API defined with this class. All routes will have this namespace as first part of the URI. See `REST Route URIs` section.\n\n#### `idName`\n_String_ _required_\n\nID name of the resource. See `REST Route URIs` section.\n\n#### Route Decorators\n\n```typescript\ncreate (params: RestParams, routeParams?: T): MethodDecorator\ngetOne (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\ngetList (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\nupdate (params: RestParams, routeParams?: T): MethodDecorator\nupdateAll (params: RestParams, routeParams?: T): MethodDecorator\nremove (params: RestParams, routeParams?: T): MethodDecorator\nsearch (params: RestParamsWithResponse, routeParams?: T): MethodDecorator\naction (action: string, params: RestParams, routeParams?: T): MethodDecorator\n```\n- `params` _required_ - See `RestParams` and `RestParamsWithResponse`.\n- `routeParams` _optional_ - See `ExposedRouteParams`, `TokenProtectedRouteParams` and `RouteParams`.\n\n#### `create` decorator\n\nDefine a `POST` route with `201` response code. It can respond with a created entity.\n\n#### `getOne` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a single entity. Entity ID is provided as path parameter.\n\n#### `getList` decorator\n\nDefine a `GET` route with `200` response code. It should respond with a list of entities.\n\n#### `update` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entity. Entity ID is provided as path parameter.\n\n#### `updateAll` decorator\n\nDefine a `PUT` route with `200` response code. It can respond with an updated entities. Entity ID is NOT provided as path parameter.\n\n#### `remove` decorator\n\nDefine a `DELETE` route with `204` response code. It should respond with empty body. Entity ID is provided as path parameter.\n\n#### `search` decorator\n\nDefine a `POST` route with `200` response code. It should respond with a list of entities. Body of the request contains search parameters.\n\n#### `action` decorator\n\nDefine a `POST` route with `200` response code. This is used to define action route which modifies the entity.\n\n### REST Route URIs\n\nREST Route URIs are generated by combining access level, controller namespace, ID name, route and command. Route and command are optional. The format is:\n```\n/<access-level>/<controller-namespace>/<route>/<command>\n```\nfor collection APIs and\n```\n/<access-level>/<controller-namespace>/<route>/:<id-name>/<command>\n```\nfor single resource APIs.\n\nAny empty part of the URI will be removed. For example if route and command are not defined the URIs will be:\n```\n/<access-level>/<controller-namespace>\n/<access-level>/<controller-namespace>/:<id-name>\n```\n\n### Route Interfaces\n\n#### RouteParams\n\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### ExposedRouteParams\n\n- `version` _optional_ - Used for route versioning. The letter `v` is added before the number. Defaut value is `1`.\n- `tag` _optional_ - Used for swagger generation. Default value is `Exposed`.\n- `description` _optional_ - Used for swagger generation.\n- `response` _optional_ - Used for swagger generation. Check `ResponseOptions`.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n\n#### TokenProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- `scopes` _optional_ - required scopes allowed to access this route\n- `roles` _optional_ - required roles allowed to access this route\n- `claims` _optional_ - JWT needs to contain all of these claims\n- `authorizeTokenData` _optional_ - callback method for custom JWT inspection\n- \\+ the ones from _ExposedRouteParams_\n\n#### GbacProtectedRouteParams\nCan be used to specify additional requirements for various JWT claims:\n\n- `entityType` _optional_ - only allow access using Client Credentials / Identity access token\n- \\+ the ones from _ExposedRouteParams_\n\n#### RestParams\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _optional_ - Response `ref` to use for swagger generation.\n\n#### RestParamsWithResponse\n\n- `route` _optional_ - The last segment of the URI entity path part. See `REST Route URIs` section.\n- `command` _optional_ - The last segment of the URI path. See `REST Route URIs` section.\n- `description` _required_ - Description to use for swagger generation.\n- `responseDescription` _required_ - Response description to use for swagger generation.\n- `errors` _optional_ - List of whitelisted errors for this route. A list should contain classes which inherit from HttpError. In the class constructor prototype should be set explicitly (as explained [here](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n- `response` _required_ - Response `ref` to use for swagger generation.\n\n### Extra parameter decorators\n\n#### MultiBody\n\n[routing-controllers](https://github.com/typestack/routing-controllers) package defines a set of decorators to inject various parameters to route handlers. One of them is a [Body](https://github.com/typestack/routing-controllers#inject-request-body) parameter decorator which injects the request body. `Body` decorator has a limitation and it can be defined for one type only. Sometimes we expect request body which can be multiple different types based on a property value contained within the body.\n\nWe defined a new decorator `MultiBody` which defines a set of possible types and rules to select them.\n\n```typescript\nMultiBody (targetTypes: ClassConstructor<any>[], options?: BodyOptions): ParameterDecorator\nMultiBody (typeOptions: MultiTypeOptions, options?: BodyOptions): ParameterDecorator\n```\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nOr we can use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nExample:\n``` typescript\n  @JsonController()\n  class BodyTestController {\n    @Route('post', '/body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeBodyTestRoute (@Body() body: BodyBase): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyTestRoute (@MultiBody([Body1, Body2, Body3]) body: Body1 | Body2 | Body3): Promise<ResponseClass> {\n      ...\n    }\n\n    @Route('post', '/multi-body-custom-test-route', { response: { schemaRef: ResponseClass } })\n    async routeMultiBodyCustomTestRoute (@MultiBody({\n      discriminator: {\n        property: 'bodyType',\n        subTypes: [\n          { name: 'body-A', value: CustomBody1 },\n          { name: 'body-B', value: CustomBody2 },\n          { name: 'body-C', value: CustomBody3 }\n        ]\n      }\n    }) body: CustomBody1 | CustomBody2 | CustomBody3): Promise<ResponseClass> {\n      ...\n    }\n  }\n```\n\n### Extra validation decorators\n\n#### OrUndefined\n\n```typescript\nOrUndefined(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is undefined so the undefined value is accepted. When generating swagger it will remove the property from required list.\n\n#### OrNull\n\n```typescript\nOrNull(validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to disable validation when the value is null so the null value is accepted. When generating swagger it will add `nullable: true` to the property descriptor.\n\n#### IsNumberOrString\n\n```typescript\nIsNumberOrString(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be either a number or a string. It is identical to a combination of `IsNumber` and `IsString` validators defined in [class-validator](https://github.com/typestack/class-validator#validation-decorators) package.\n\n#### IsInstanceOf\n\n```typescript\nIsInstanceOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsArrayOf\n\n```typescript\nIsArrayOf(targetType: ClassConstructor<any>, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to an array of items of a scpecific type. It is a combination of three validators `IsInstance`, `ValidateNested` and `IsDefined`.\n\n#### IsOneInstance\n\n```typescript\nIsOneInstance(targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate the property to be one of scpecified types.\n\n#### IsOneInstanceOf\n\n```typescript\nIsOneInstanceOf (targetTypes: ClassConstructor<any>[], validationOptions?: ValidationOptions): PropertyDecorator\nIsOneInstanceOf (typeOptions: MultiTypeOptions, validationOptions?: ValidationOptions): PropertyDecorator\n```\n\nThis validator is used to validate and convert the property to one of the specified types. It is a combination of three validators `IsOneInstance`, `ValidateNested` and `IsDefined`.\n\nTwo different overloads are defined. If we define an array of types `MultiTypeOptions` will be generated automatically like this\n```\n{\n  discriminator: {\n    property: 'type',\n    subTypes: targetTypes.map((t: ClassConstructor<any>) => ({ value: t, name: _.kebabCase(t.name) }))\n  },\n  keepDiscriminatorProperty: true,\n}\n```\n\nFor example when using `@IsOneInstanceOf([Type1, Type2, Type3])` `typeOptions` would be\n``` typescript\n{\n  discriminator: {\n    property: 'type',\n    subTypes: [\n      { value: Type1, name: 'type1' },\n      { value: Type2, name: 'type2' },\n      { value: Type3, name: 'type3' }\n    ]\n  },\n  keepDiscriminatorProperty: true\n}\n```\n\nWe can also use it with `MultiTypeOptions` and have more control over how types will be selected. `MultiTypeOptions` type is used the same way as described in [class-transformer](https://github.com/typestack/class-transformer#providing-more-than-one-type-option) package.\n\nStorage\n--------\n\n### MySql\n\nTODO\n\n### Redis\n\nTODO\n\nTransport\n-------------\nFor apps using Atlas, SNS/SQS handling is defined with list of handler classes in `atlas.init(options)`. Each handler class defines one or more event handlers which must be decorated with `EventHandler` decorator. Event param can be obtained by decorating event handler's params with one of the param decorators `QueueMessage` or `MessageBody`. `MessageBody` decorator uses a type of the param to validate the message after being parsed from JSON. Message type should be defined using `class-validator` decorators you can import from `micro-kit-atlas/rounting`.\n\n### Basic use\nhandler.ts\n```typescript\n    import { EventHandler, MessageBody } from 'micro-kit-atlas/transport'\n    import { IsString } from 'micro-kit-atlas/routing'\n\n    const EVENT_TOPIC: string = 'EVENT_TOPIC'\n\n    export class FirstMessageBody {\n      @IsString() stringParam!: string\n    }\n\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() message: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n    }\n```\napp.ts\n```typescript\n    import { Lib , init } from 'micro-kit-atlas'\n    import { FirstHandler } from './handler'\n\n    const options: Lib.Config = {\n      name: 'check_status',\n      routing: {\n        controllers: []\n      },\n      transport: {\n        handlers: [FirstHandler]\n      },\n    }\n\n    export async function initService (): Promise<any> {\n      const app = await init(options)\n      const inst = await app.listen(8080, () => {\n        console.log('running on port:', 8080)\n      })\n      return inst\n    }\n\n    initService()\n      .then(() => {\n        logger.info('Running server')\n      })\n      .catch((err: Error) => {\n        logger.error(err)\n        process.exit(1)\n      })\n```\n\n### Decorators\n\n#### EventHandler decorator\n\nDecorator used to mark a class method as an event handler.\n\n```typescript\nEventHandler: (topic: string, options?: EventHandlerOptions): MethodDecorator\n```\n\n- `topic` _required_ - Name of the event topic\n- `options` _optional_ - Options used when registering event with `subscribeToEvent` function from `micro-kit-aws-queue` package.\n\n#### QueueMessage decorator\n\nDecorator used to mark an event handler's parameter to contain entire queue message object.\n\n```typescript\nQueueMessage (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@QueueMessage() message: Transport.QueueMessage): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageId decorator\n\nDecorator used to mark an event handler's parameter to contain queue message id.\n\n```typescript\nMessageId (): ParameterDecorator\n```\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageId() messageId: string): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n#### MessageBody decorator\n\nDecorator used to mark an event handler's parameter to contain parsed queue message data.\n\n```typescript\nMessageBody (targetType?: ClassConstructor<any>, options?: MessageBodyOptions): ParameterDecorator\n```\n\n- `targetType` _optional_ - Target type to be used to convert and validate a parsed JSON object. If not provided type of the parameter is used.\n- `options` _optional_ - See `MessageBodyOptions`.\n\nExample:\n```typescript\n    export class FirstHandler () {\n      @EventHandler(EVENT_TOPIC)\n      async eventHandler(@MessageBody() messageBody: FirstMessageBody): Promise<void> {\n        // event handler code\n      }\n      async eventHandler2(@MessageBody(FirstMessageBody) messageBody: any): Promise<void> {\n        // event handler code\n      }\n    }\n```\n\n### Transport Interfaces\n\n#### BaseParamOptions\n\n  classTransform?: ClassTransformOptions\n  validate?: boolean | ValidatorOptions\n\n- `classTransform` _optional_ - `ClassTransformOptions` object used when transforming object to class using [class-transformer](https://github.com/typestack/class-transformer)\n- `validate` _optional_ - If true, [class-validator](https://github.com/typestack/class-validator) will be used to validate param object. If validation options are given then it means validation will be applied. Default is `true`.\n\n#### MessageBodyOptions\n\nInherits properties from `BaseParamOptions`.\n\nUtility\n-------------\n\nAtlas provides some utility modules.\n\n# Obfuscator\n## Usage\n### Importing & enabling\nTo use this in your project you must enable it by passing `obfuscataor: true` to the Atlas configuration object.\n\n```typescript\n// to import the obfuscator functions\nimport * as obfuscator from 'micro-kit-atlas/obfuscator'\n```\n\n### String obfuscating\n```typescript\nconst obfuscated_item: obfuscator.ObfuscatedItem = await obfuscator.obfuscateSingle('string')\n\nconst obfuscated_string: string = obfuscated_item.obfuscated\n```\n\n### String array obfuscating\n```typescript\nconst strings: string[] = ['string1', 'string2', 'string3']\n\nconst obfuscated_items: obfuscator.ObfuscatedItem[] = await obfuscator.obfuscateArray(strings)\n\nobfuscated_items.forEach((obfuscated_item: obfuscator.ObfuscatedItem) => {\n  const obfuscated_string: string = obfuscated_item.obfuscated\n})\n```\n\n# Lodash extensions\n\n(Lodash)[https://lodash.com/] is a library we use in many of our projects to ease JS/TS development. We use it in mocha/chai testing with (chai-match-pattern)[https://github.com/originate/chai-match-pattern] extension. We add some extra matcher functions in Atlas. To enable them in your project you have to initialize the mixin. The best place to do this is in your test setup file.\n```typescript\nimport * as _ from 'lodash'\nimport { atlasLodash } from 'micro-kit-atlas';\n\n_.mixin(atlasLodash)\n```\n\nAtlas defines these matcher functions:\n```typescript\n    isNonEmptyString (value: string): boolean\n    isStringOrNumber (value: string | number): boolean\n    isStringOrNull (value: string | null): boolean\n    isNumberOrNull (value: number | null): boolean\n    isBooleanOrNull (value: boolean | null): boolean\n    isUuid (value: string): boolean\n```\n","readmeFilename":"README.md","homepage":"https://gitlab.com/globalid/common/atlas#readme","repository":{"type":"git","url":"git+https://gitlab.com/globalid/common/atlas.git"},"bugs":{"url":"https://gitlab.com/globalid/common/atlas/issues"}}