diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +node_modules diff --git a/.env.local b/.env.local index f5f7314..b10f6b4 100644 --- a/.env.local +++ b/.env.local @@ -1 +1,6 @@ -PORT=8100 \ No newline at end of file +PORT=8100 +OTEL_COLLECTOR_HOST=localhost +OTEL_COLLECTOR_PORT=4317 +#OTEL_COLLECTOR_HOST=http://otel-collector.dev.globoi.com +#OTEL_COLLECTOR_PORT=55680 +OTEL_EXPORTER_SERVICE=backstage-functions diff --git a/.gitignore b/.gitignore index 3fa43e7..3d9793b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ node_modules .DS_Store dump.rdb coverage -npm-debug.log \ No newline at end of file +npm-debug.log +.nyc_output \ No newline at end of file diff --git a/.node-version b/.node-version deleted file mode 100644 index 910f631..0000000 --- a/.node-version +++ /dev/null @@ -1 +0,0 @@ -8.9.1 \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 9df50f3..d1ca29e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,14 +5,9 @@ cache: - node_modules node_js: - "7" - - "8.9.1" + - "8.13.0" - "8" - "node" -notifications: - email: - - backstage1@corp.globo.com - slack: - secure: RGXv00o6a2lTXeBN0YvMkADgDpTxrSl0zNjZ/czu98ADwjJIt+Omsj9CqKjpUkQYjZNNOkm+Ak+WYnsHHe3LA+hJIVshFs0HyOlTo400AAK+q3w4YiAbt60e/a3efsqyS3hRm6HwwNTgRTHWQj2h86i/nHPU0krA4R7nI7K0RgrowFCeJmZkOOB8uAj0SYX30/qKMfMWV7V4uH0L+lrtNY8lKgX4Lr54v/J2JpeP8VvB9h1jRcYdLfMBayYvNnrMUCRFPyTpky27WGY97SLMje1cILPfSfXoXJJPxZnUoP9bjF5Eauts+wHjh5ULjCDSev/AuJ6Z2p6qjTPsFx8Qrr/wERl1NyUvajyheLOpKr30dyzLZ0EFYrHlCB0pmodbdsuo9x/flCqLUaVL+djPEibRgTt08Del63dqsM2YY0xMufk87ivPEJHccHBa3ym3iFuQgTmeGGhSNmxrnH+wQnxnRyj5ofgQkx1sSlQj+84qFSMrIIWvEO9cnIhLti3rUirryiPElWJepVMuRpfUJ7QQ8mT+yM/o62cVcK/s4Y5nd3myaPX12qPxKBW2T6eqWiSo5QdLSKDDQgIrtDcs1P8cvp1UJV8scTqrxGa3Yu3qVOxnpvLIn0FWL6UvPysmaxJJVJ34rtMQRX7y7gyx7aAm2bZKBbNLhS+J2HCsVJw= env: - CXX=g++-4.8 REDIS_ENDPOINT=redis://localhost:6379/0 services: diff --git a/Dockerfile b/Dockerfile index 83e9b7e..2d67bb2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,4 @@ -FROM mhart/alpine-node:6.10.2 - +FROM mhart/alpine-node:8.15.1 RUN apk add --no-cache make gcc g++ python WORKDIR /application/functions ADD lib lib @@ -7,6 +6,3 @@ ADD package.json . ADD npm-shrinkwrap.json . RUN npm install - -EXPOSE 8100 -CMD ["node", "lib/app.js"] diff --git a/Makefile b/Makefile index 93f05d0..061fa85 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: run setup test setup_upgrade install_node setup_nvm lint clean +.PHONY: run run-sandbox setup test setup_upgrade install_node setup_nvm lint clean DESIRED_NODE_VERSION = v$(shell cat .node-version) CURRENT_NODE_VERSION = $(shell node --version) @@ -19,10 +19,42 @@ setup: install_node run: npm run start_dev +run-sandbox: + npm run start_sandbox + test: npm test $(MAKE) lint +run-local-jaeger: + - docker rm -f /jaeger + docker run -d --name jaeger \ + -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \ + -p 5775:5775/udp \ + -p 6831:6831/udp \ + -p 6832:6832/udp \ + -p 5778:5778 \ + -p 16686:16686 \ + -p 14268:14268 \ + -p 14250:14250 \ + -p 9411:9411 \ + jaegertracing/all-in-one:1.18 + xdg-open http://localhost:16686/search + +rund: + docker-compose up -d + +stopd: + docker-compose down + +testd: stopd + @echo 'Starting test containers' + docker-compose -f docker-compose-test.yml up -d + @echo 'Running tests in container' + @docker exec -t functions_app_test make test + @echo 'Stopping test containers' + docker-compose -f docker-compose-test.yml down -v + setup_upgrade: clean npm install npm shrinkwrap @@ -60,7 +92,7 @@ clean: -rm -rf node_modules docker_build: - docker build -t globobackstage/functions . + docker build -t globocom/functions . docker_push: - docker push globobackstage/functions + docker push globocom/functions diff --git a/Procfile.sandbox b/Procfile.sandbox new file mode 100644 index 0000000..751bacc --- /dev/null +++ b/Procfile.sandbox @@ -0,0 +1 @@ +web: ./node_modules/.bin/nodemon lib/app.js diff --git a/README.md b/README.md index 3d7f71e..6e18ce2 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![Build Status](https://travis-ci.org/backstage/functions.png?branch=master)](https://travis-ci.org/backstage/functions) -[![Coverage Status](https://coveralls.io/repos/github/backstage/functions/badge.svg?branch=master)](https://coveralls.io/github/backstage/functions?branch=master) +[![Build Status](https://travis-ci.org/globocom/functions.png?branch=master)](https://travis-ci.org/globocom/functions) +[![Coverage Status](https://coveralls.io/repos/github/globocom/functions/badge.svg?branch=master)](https://coveralls.io/github/globocom/functions?branch=master) # Backstage Functions Backstage Functions is an Open Source [Serverless](http://martinfowler.com/articles/serverless.html) Platform able to store and execute code. @@ -22,7 +22,7 @@ It uses the [Backstage Functions Sandbox](https://github.com/backstage/functions ## Running locally without Docker ### Requirements - Redis 3.0+ -- NodeJS 6.10.2 +- NodeJS 8.13.0 ### Download the project ```bash @@ -39,6 +39,14 @@ make setup make run ``` +## Configuration + +To format your log in `json`, please run: + +```sh +export LOG_APP_FORMAT=json +``` + ## Running locally via Docker ### Requirements - Docker 1.12+ @@ -57,7 +65,7 @@ docker-compose up ``` ## How to use -### Creating a function +### Function Structure Your function will have a file, which you define any name you want, and it has to have a function called `main`, with two parameters: `req` and `res`. Req represents the `Request` and Res represents the `Response`. At the end of your code, you'll have to use the `send` method. @@ -68,25 +76,16 @@ function main(req, res) { res.send({ say: `Hello ${name}!` }) } ``` +### Setting a function -To store your function, you can make a `POST` request to `/functions/:namespace/:name`: -```bash -curl -i -X POST http://localhost:8100/functions/example/hello-world \ - -H 'content-type: application/json' \ - -d '{"code":"function main(req, res) {\n const name = (req.body && req.body.name) || \"World\"\n res.send({ say: `Hello ${name}!` })\n}\n"}' -``` - -*ps: if already exists, it will not be updated* - -### Updating a function -To update your function, you can make a `PUT` request to `/functions/:namespace/:name`: +To set your function, you can make a `PUT` request to `/functions/:namespace/:name`: ```bash curl -i -X PUT http://localhost:8100/functions/example/hello-world \ -H 'content-type: application/json' \ -d '{"code":"function main(req, res) {\n const name = (req.body && req.body.name) || \"World\"\n res.send({ say: `Hello ${name}! Nice meeting you...` })\n}\n"}' ``` -*ps: if it doesn't exists, it will be created* +*Ps: if it doesn't exists, it will be created* ### Deleting a function To delete your function, you can make a `DELETE` request to `/functions/:namespace/:name`: diff --git a/conf/redis-cluster/node1/sentinel.conf b/conf/redis-cluster/node1/sentinel.conf index 0f25463..f23fcd7 100644 --- a/conf/redis-cluster/node1/sentinel.conf +++ b/conf/redis-cluster/node1/sentinel.conf @@ -10,5 +10,13 @@ port 16380 sentinel monitor redis-cluster 127.0.0.1 6380 2 sentinel down-after-milliseconds redis-cluster 5000 sentinel failover-timeout redis-cluster 10000 -sentinel config-epoch redis-cluster 0 -dir . +sentinel config-epoch redis-cluster 2 +dir "/home/markiing/Globo/functions" +# Generated by CONFIG REWRITE +maxclients 4064 +sentinel leader-epoch redis-cluster 0 +sentinel known-slave redis-cluster 127.0.0.1 6382 +sentinel known-slave redis-cluster 127.0.0.1 6381 +sentinel known-sentinel redis-cluster 127.0.0.1 16381 e42de72f23291aac6a8684bbb24ab071c35e03a1 +sentinel known-sentinel redis-cluster 127.0.0.1 16382 227a4dccd28524dd5ca3aff6610a8d2fd9009e99 +sentinel current-epoch 2 diff --git a/conf/redis-cluster/node2/sentinel.conf b/conf/redis-cluster/node2/sentinel.conf index 0346be8..3267d6c 100644 --- a/conf/redis-cluster/node2/sentinel.conf +++ b/conf/redis-cluster/node2/sentinel.conf @@ -11,4 +11,12 @@ sentinel monitor redis-cluster 127.0.0.1 6380 2 sentinel down-after-milliseconds redis-cluster 5000 sentinel failover-timeout redis-cluster 10000 sentinel config-epoch redis-cluster 2 -dir . +dir "/home/markiing/Globo/functions" +# Generated by CONFIG REWRITE +maxclients 4064 +sentinel leader-epoch redis-cluster 0 +sentinel known-slave redis-cluster 127.0.0.1 6381 +sentinel known-slave redis-cluster 127.0.0.1 6382 +sentinel known-sentinel redis-cluster 127.0.0.1 16380 94e5255bc9dcb31d5ca0d553d41b4f7b1e3d2438 +sentinel known-sentinel redis-cluster 127.0.0.1 16382 227a4dccd28524dd5ca3aff6610a8d2fd9009e99 +sentinel current-epoch 2 diff --git a/conf/redis-cluster/node3/sentinel.conf b/conf/redis-cluster/node3/sentinel.conf index d7d61fa..0a24e02 100644 --- a/conf/redis-cluster/node3/sentinel.conf +++ b/conf/redis-cluster/node3/sentinel.conf @@ -12,4 +12,12 @@ sentinel down-after-milliseconds redis-cluster 5000 sentinel failover-timeout redis-cluster 10000 sentinel config-epoch redis-cluster 2 -dir . +dir "/home/markiing/Globo/functions" +# Generated by CONFIG REWRITE +maxclients 4064 +sentinel leader-epoch redis-cluster 0 +sentinel known-slave redis-cluster 127.0.0.1 6381 +sentinel known-slave redis-cluster 127.0.0.1 6382 +sentinel known-sentinel redis-cluster 127.0.0.1 16380 94e5255bc9dcb31d5ca0d553d41b4f7b1e3d2438 +sentinel known-sentinel redis-cluster 127.0.0.1 16381 e42de72f23291aac6a8684bbb24ab071c35e03a1 +sentinel current-epoch 2 diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml deleted file mode 100644 index c1ac3c1..0000000 --- a/docker-compose-dev.yml +++ /dev/null @@ -1,26 +0,0 @@ -version: '2' -services: - web: - container_name: functions_app_dev - build: . - ports: - - "127.0.0.1:8100:8100" - networks: - - functions_net_dev - environment: - REDIS_ENDPOINT: redis://redis:6379/0 - depends_on: - - redis - redis: - container_name: functions_db_dev - image: redis - volumes: - - functions_vol_dev:/data - networks: - - functions_net_dev - -volumes: - functions_vol_dev: - -networks: - functions_net_dev: diff --git a/docker-compose-test.yml b/docker-compose-test.yml new file mode 100644 index 0000000..1f1bd8a --- /dev/null +++ b/docker-compose-test.yml @@ -0,0 +1,31 @@ +version: '3' +services: + web: + container_name: functions_app_test + image: globocom/functions + ports: + - "127.0.0.1:8100:8100" + networks: + - functions_net_test + environment: + REDIS_ENDPOINT: redis://redis:6379/0 + depends_on: + - redis + command: node lib/app.js + volumes: + - .:/application/functions + - node_test_vol:/application/functions/node_modules + redis: + container_name: functions_db_test + image: redis + volumes: + - redis_test_vol:/data + networks: + - functions_net_test + +volumes: + redis_test_vol: + node_test_vol: + +networks: + functions_net_test: diff --git a/docker-compose.yml b/docker-compose.yml index 4e4d068..a556eba 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,26 +1,31 @@ -version: '2' +version: '3' services: web: container_name: functions_app - image: globobackstage/functions + image: globocom/functions ports: - "8100:8100" networks: - functions_net depends_on: - redis + command: node lib/app.js + volumes: + - .:/application/functions + - node_vol:/application/functions/node_modules environment: REDIS_ENDPOINT: redis://redis:6379/0 redis: container_name: functions_db image: redis volumes: - - functions_vol:/data + - redis_vol:/data networks: - functions_net volumes: - functions_vol: + redis_vol: + node_vol: networks: functions_net: diff --git a/lib/app.js b/lib/app.js index d935335..d121b3e 100644 --- a/lib/app.js +++ b/lib/app.js @@ -1,11 +1,19 @@ const cluster = require('cluster'); +const express = require('express'); const log = require('./support/log'); const routes = require('./http/routes'); +const MetricsRouter = require('./http/routers/MetricsRouter'); const config = require('./support/config'); const globalImport = require('./support/globalImport'); const setupHTTPClient = require('./support/setupHTTPClient'); if (cluster.isMaster && config.useNodeCluster) { + const metricsApp = express(); + metricsApp.use('/metrics', MetricsRouter); + metricsApp.listen(config.metricsPort, () => { + log.info(`Functions metrics is listening on port ${config.metricsPort}`); + }); + // Fork workers. for (let i = 0; i < config.numCPUs; i += 1) { cluster.fork(); @@ -27,6 +35,6 @@ if (cluster.isMaster && config.useNodeCluster) { globalImport(); // Makes sure to load some support libraries to run the functions setupHTTPClient(); routes.listen(config.port, () => { - log.info(`Functions beating on port ${config.port}`); + log.info(`Functions is listening on port ${config.port}`); }); } diff --git a/lib/domain/BackstageFunctionProvider.js b/lib/domain/BackstageFunctionProvider.js new file mode 100644 index 0000000..f7525da --- /dev/null +++ b/lib/domain/BackstageFunctionProvider.js @@ -0,0 +1,52 @@ +const { reportError } = require("../support/tracing"); +const SpanConsoleWrapper = require("./SpanConsoleWrapper"); + +class BackstageFunctionProvider { + + async run(req) { + let code; + const { namespace, id, filename, logStorage, span } = req.params + const memoryStorage = req.app.get('memoryStorage'); + const sandbox = req.app.get('sandbox'); + + try { + code = await memoryStorage.getCodeByCache(namespace, id, { + preCache: (preCode) => { + preCode.script = sandbox.compileCode(filename, preCode.code); + return preCode; + }, + }); + + + + if (!code) { + const error = new Error(`Code '${namespace}/${id}' is not found`); + error.statusCode = 404; + // reportError(span, error); + throw error; + } + } catch (err) { + // reportError(span, err); + err.statusCode = err.statusCode || 500 + err.error = err.message + throw err + } + + const options = { + console: new SpanConsoleWrapper(logStorage.console, span), + env: code.env, + span, + }; + + const result = await sandbox.runScript(code.script, req, options) + return { + ...result, + headers: { + ...result.headers, + 'x-serverless-engine': 'bs-functions; javascript sandbox legacy;' + } + }; + } +} + +module.exports = BackstageFunctionProvider; diff --git a/lib/domain/ErrorTracker.js b/lib/domain/ErrorTracker.js index 946f042..b6acbc2 100644 --- a/lib/domain/ErrorTracker.js +++ b/lib/domain/ErrorTracker.js @@ -1,4 +1,5 @@ const raven = require('raven'); +const request = require('request'); const https = require('https'); const { parseError } = require('raven/lib/parsers'); const { getModules, getCulprit } = require('raven/lib/utils'); @@ -10,9 +11,18 @@ const log = require('../support/log'); raven.config(); raven.disableConsoleAlerts(); const globalSentryDSNClient = new raven.Client(); +const cache = {}; ravenHTTPSTransport.agent = https.globalAgent; +function getRavenClient(DSN) { + if (!cache[DSN]) { + cache[DSN] = new raven.Client(DSN); + } + + return cache[DSN]; +} + function applyContext(frame, lines) { const linesOfContext = 7; const realLine = frame.lineno - 2; @@ -66,11 +76,19 @@ function filterFrames(ctx, filename, code) { }); if (frames.length > 0) { - ctx.culprit = getCulprit(frames[frames.length - 1]); + ctx.culprit = `${filename}: ${getCulprit(frames[frames.length - 1])}`; + } else { + ctx.culprit = filename; } exception.stacktrace.frames = frames; } + + ctx.message = `${filename}: ${ctx.message}`; +} + +function filterStatusCode(statusCode) { + return statusCode !== 408 && statusCode < 500; } class ErrorTracker { @@ -82,10 +100,14 @@ class ErrorTracker { this.tags = tags; this.breadcrumbs = breadcrumbs || []; - this.sentryClient = sentryClient || globalSentryDSNClient; + this.sentryClient = sentryClient || getRavenClient(sentryDSN); } notify(err) { + if (err.statusCode && filterStatusCode(err.statusCode)) { + return; + } + parseError(err, { extra: this.extra, tags: this.tags }, (ctx) => { filterFrames(ctx, this.filename, this.code); @@ -94,7 +116,6 @@ class ErrorTracker { ctx.modules = getSandboxModules(); if (this.sentryDSN) { - this.sentryClient.config(this.sentryDSN); ctx.event_id = this.sentryClient.generateEventId(); this.sentryClient.send(ctx, (publishErr) => { if (publishErr) { @@ -106,6 +127,39 @@ class ErrorTracker { notifySentryGlobal(ctx); }); } + + static get name() { + return 'Sentry'; + } + + static async ping() { + const dsn = globalSentryDSNClient.dsn; + + if (!dsn) { + return 'SENTRY_DSN is not setted yet'; + } + + const url = `${dsn.protocol}://${dsn.host}/api/0/`; + + return new Promise((resolve, reject) => { + request({ + url, + timeout: 3000, + }, (err, response) => { + if (err) { + reject(err); + return; + } + + if (response.statusCode === 200) { + resolve('OK'); + return; + } + + reject(new Error(`HTTP status: ${response.statusCode} requesting sentry`)); + }); + }); + } } module.exports = ErrorTracker; diff --git a/lib/domain/FunctionProvider.js b/lib/domain/FunctionProvider.js new file mode 100644 index 0000000..a46381d --- /dev/null +++ b/lib/domain/FunctionProvider.js @@ -0,0 +1,50 @@ +const BackstageFunctionProvider = require('./BackstageFunctionProvider'); +const GoogleFunctionProvider = require('./GoogleFunctionProvider'); + + +const FunctionProviders = { + BackstageProvider: 'backstage-executor', + GoogleProvider: 'google-executor' +} + +class FunctionProvider { + + static toEnum(providerStr) { + let providerEnum; + switch(providerStr) { + case FunctionProviders.GoogleProvider.toString(): + providerEnum = FunctionProviders.GoogleProvider; + break; + default: + providerEnum = FunctionProviders.BackstageProvider; + break; + } + return providerEnum; + } + + run() { + throw Error("Class method not implemented"); + } +} + +class FunctionProviderFactory { + + getFunctionProvider(providerStr) { + let provider; + const providerEnum = FunctionProvider.toEnum(providerStr); + switch(providerEnum) { + case FunctionProviders.GoogleProvider: + provider = new GoogleFunctionProvider() + break; + default: + provider = new BackstageFunctionProvider(); + break; + } + return provider; + } +} + +module.exports = { + FunctionProvider: FunctionProvider, + FunctionProviderFactory: FunctionProviderFactory +} diff --git a/lib/domain/GoogleFunctionProvider.js b/lib/domain/GoogleFunctionProvider.js new file mode 100644 index 0000000..f595e89 --- /dev/null +++ b/lib/domain/GoogleFunctionProvider.js @@ -0,0 +1,127 @@ +const config = require("../support/config"); +const fetch = require('node-fetch'); +const { GoogleAuth } = require("google-auth-library"); +const { FunctionServiceClient } = require('@google-cloud/functions').v2; +// const { request } = require('gaxios'); + +const log = require("../support/log"); + +class GoogleFunctionProvider { + constructor() { + } + + async authenticate(url){ + try{ + const sa_auth = JSON.parse(Buffer.from(config.googleCloudCredentials, "base64").toString('ascii')) + const client = new GoogleAuth().fromJSON(sa_auth); + const token = await client.fetchIdToken(url) + return `Bearer ${token}` + }catch(err){ + throw err + } + } + + async run(req) { + try { + const zoneId = "us-central1" + const projectId = "removed" + const { namespace, id } = req.params + const { body } = req + const url = `https://${zoneId}-${projectId}.cloudfunctions.net/${namespace}_${id}`; + + const token = await this.authenticate(url) + + const response = await fetch(url, { + method: "POST", + body: JSON.stringify(body), + headers: { + "Content-Type": "application/json", + "Authorization": token + } + }) + + const contentType = response.headers['content-type']; + + const data = (contentType && contentType.includes('application/json')) ? await response.json() : await response.text() + + return { + status: response.status, + headers: { + ...Object.fromEntries(response.headers), + 'x-serverless-engine': 'bs-functions; go v1.21.1;' + }, + body: data + } + } catch (ex) { + throw ex + } + } + + async getEnvironmentVariables(projectId, functionName){ + + } + + async putEnvironmentVariables(projectId, functionName, variables){ + const url = `https://cloudfunctions.googleapis.com/v1/projects/${projectId}/locations/-/functions/${functionName}` + + const token = await authenticate(url) + + const response = await request({ + url, + method: "POST", + data: {}, + headers: { + "Content-Type": "application/json", + "Authorization": token + } + }) + + return response + } + + async deployFunction(){ + const projectId = "removed" + const zoneId = "us-central1" + const functionName = "backstage-kernel_hello-world" + const entryPoint = 'helloHttp'; + const runtime = 'nodejs20'; + + const keyFilePath = './backday.json'; + + const auth = new GoogleAuth({ + keyFile: keyFilePath, + }); + const client = new FunctionServiceClient({ auth }); + + const functionObject = { + "name": `projects/${projectId}/locations/${zoneId}/functions/${functionName}`, + "buildConfig": { + "entryPoint": entryPoint, + "runtime": runtime, + "source": { + "storageSource": { + "bucket": 'gcf-v2-sources-391036631868-us-central1', + "object": 'backstage-kernel_hello-world/function-source.zip', + "generation": '1700773129721671' + }, + "source": 'storageSource' + } + }, + "serviceConfig": { + "environmentVariables": { + "test": "test", + }, + }, + } + const request = { + "function": functionObject, + }; + + const [operation] = await client.updateFunction(request); + const [response] = await operation.promise(); + console.log(response); + return + } +} + +module.exports = GoogleFunctionProvider; diff --git a/lib/domain/LogStorage.js b/lib/domain/LogStorage.js index 890f983..69dcbf2 100644 --- a/lib/domain/LogStorage.js +++ b/lib/domain/LogStorage.js @@ -4,9 +4,9 @@ const { } = require('@globocom/backstage-functions-sandbox'); const { STATUS_CODES } = require('http'); -const gelf = require('gelf-pro'); +const Gelf = require('gelf'); const config = require('../support/config'); - +const log = require('../support/log'); function extractHTTPFields(req) { const fields = {}; @@ -28,21 +28,81 @@ class StdoutLogStorage { class GelfLogStorage { constructor(namespace, id, req) { - this.stream = new MemoryStream(); + this.stream = new MemoryStream(config.log.maxFullMessage); this.console = new PrefixLog(null, this.stream, this.stream); this.file = `${namespace}/${id}.js`; this.namespace = namespace; this.fields = extractHTTPFields(req); + this.gelfClients = GelfLogStorage.prepareGelfClients(); + this.logLevels = { + emerg: 0, + panic: 0, + alert: 1, + crit: 2, + error: 3, + err: 3, + warn: 4, + warning: 4, + notice: 5, + info: 6, + debug: 7, + }; + } + + static prepareGelfClients() { + if (GelfLogStorage.gelfClientList) { + return GelfLogStorage.gelfClientList; + } + + let client; + GelfLogStorage.gelfClientList = []; + + for (const host of config.log.hosts) { + client = new Gelf({ + graylogHostname: host, + graylogPort: config.log.port, + connection: 'wan', + maxChunkSizeWan: config.log.maxChunkSize, + }); + + client.on('error', (err) => { + log.error('Failed to send log graylogServer err: %s', err); + }); + + GelfLogStorage.gelfClientList.push(client); + } + + return GelfLogStorage.gelfClientList; + } + + static prepareExtraFields(extra) { + const auxObject = {}; + + Object.keys(extra).forEach((key) => { + if (key.startsWith('_')) { + auxObject[key] = extra[key]; + } else { + const keyName = `_${key}`; + auxObject[keyName] = extra[key]; + } + }); + + return auxObject; + } + + sendLog(message) { + for (const gelfClient of this.gelfClients) { + gelfClient.emit('gelf.log', message); + log.debug('sent to gelfServer:', gelfClient.config.graylogHostname, 'message:', message); + } } flush({ status, requestTime }) { - const message = Object.assign({ - full_message: this.stream.buffer.join(''), - status, - request_time: requestTime, - group: this.namespace, - file: this.file, - }, this.fields); + let fullMessage = this.stream.buffer.join(''); + + if (this.stream.truncated) { + fullMessage += '\ntruncated'; + } let level = 'info'; if (status >= 500) { @@ -51,7 +111,22 @@ class GelfLogStorage { level = 'warn'; } const statusMsg = STATUS_CODES[status]; - gelf[level](`Function "${this.file}" was executed with status ${status} "${statusMsg}"`, message); + const shortMessage = `Function "${this.file}" was executed with status ${status} "${statusMsg}"`; + + const extra = Object.assign({ + status, + request_time: requestTime, + group: this.namespace, + file: this.file, + }, this.fields, config.log.fields); + + const message = Object.assign({ + full_message: fullMessage, + level: this.logLevels[level], + short_message: shortMessage, + }, GelfLogStorage.prepareExtraFields(extra)); + + this.sendLog(message); return message; } } @@ -61,12 +136,5 @@ exports.StdoutLogStorage = StdoutLogStorage; exports.GelfLogStorage = GelfLogStorage; if (config.log.type === 'gelf') { - gelf.setConfig({ - fields: config.log.fields, - adapterOptions: { - host: config.log.host, - port: config.log.port, - }, - }); exports.DefaultLogStorage = GelfLogStorage; } diff --git a/lib/domain/Metric.js b/lib/domain/Metric.js index 3666d02..4c3e9af 100644 --- a/lib/domain/Metric.js +++ b/lib/domain/Metric.js @@ -1,9 +1,103 @@ -const dgram = require('dgram'); -const config = require('../support/config'); -const log = require('../support/log'); +const prometheusClient = require('prom-client'); -const sender = dgram.createSocket('udp4'); +prometheusClient.collectDefaultMetrics(); +const buckets = [ + 0.001, + 0.002, + 0.005, + 0.010, + 0.020, + 0.050, + 0.100, + 0.200, + 0.500, + 1, + 2, + 5, + 10, + 15, + 20, +]; + +const functionRunHistogram = new prometheusClient.Histogram({ + name: 'backstage_functions_function_run_duration_seconds', + help: 'How many time spent to run a function in seconds', + buckets, + labelNames: ['namespace', 'id'], +}); + +const functionOverviewRunHistogram = new prometheusClient.Histogram({ + name: 'backstage_functions_overview_run_duration_seconds', + help: 'How many time spent to run all functions in seconds', + buckets, +}); + +const functionPipelineHistogram = new prometheusClient.Histogram({ + name: 'backstage_functions_pipeline_run_duration_seconds', + help: 'How many time spent to run a function pipeline in seconds', + buckets, +}); + +const functionSetupHistogram = new prometheusClient.Histogram({ + name: 'backstage_functions_function_setup_duration_seconds', + help: 'How much time spent to setup a function in seconds', + buckets, +}); + +const functionUpdateHistogram = new prometheusClient.Histogram({ + name: 'backstage_functions_function_update_duration_seconds', + help: 'How much time spent to update a function in seconds', + buckets, + labelNames: ['status'], +}); + +function normalizeStatusCode(status) { + if (status < 200) { + return '1xx'; + } else if (status < 300) { + return '2xx'; + } else if (status < 400) { + return '3xx'; + } else if (status < 500) { + return '4xx'; + } + return '5xx'; +} + +const functionOverviewRunCounter = new prometheusClient.Counter({ + name: 'backstage_functions_overview_run_total', + help: 'What the portion of executions by status codes', + labelNames: ['status'], +}); + +const functionRunCounter = new prometheusClient.Counter({ + name: 'backstage_functions_function_run_total', + help: 'What is the status code of a function', + labelNames: ['namespace', 'id', 'status'], +}); + +const functionPipelineCounter = new prometheusClient.Counter({ + name: 'backstage_functions_pipeline_run_total', + help: 'What is the status code of pipelines', + labelNames: ['status'], +}); + +const redisLeaksCounter = new prometheusClient.Counter({ + name: 'backstage_functions_redis_leaks_total', + help: 'How many redis leaks in backstage functions', +}); + +const functionSetupCounter = new prometheusClient.Counter({ + name: 'backstage_functions_function_setup_total', + help: 'How many functions were set up', +}); + +const functionUpdateCounter = new prometheusClient.Counter({ + name: 'backstage_functions_function_update_total', + help: 'How many functions were updated with status code', + labelNames: ['status'], +}); class Metric { constructor(metric) { @@ -11,26 +105,48 @@ class Metric { this.start = Date.now(); } - finish(options) { - const spent = Date.now() - this.start; + observeFunctionRun({ namespace, id, status }) { + const spent = (Date.now() - this.start) / 1000; + const normalizedStatusCode = normalizeStatusCode(status); + + functionOverviewRunHistogram.observe(spent); + functionOverviewRunCounter.labels(normalizedStatusCode).inc(); - if (!config.metric.client) { - return spent; - } + functionRunHistogram.labels(namespace, id).observe(spent); + functionRunCounter.labels(namespace, id, normalizedStatusCode).inc(); + + return spent; + } + + observePipelineRun(status) { + const spent = (Date.now() - this.start) / 1000; + const normalizedStatusCode = normalizeStatusCode(status); + + functionPipelineHistogram.observe(spent); + functionPipelineCounter.labels(normalizedStatusCode).inc(); + } + + static observeRedisLeak() { + redisLeaksCounter.inc(); + } + + observeFunctionSetup() { + const spent = (Date.now() - this.start) / 1000; + + functionSetupHistogram.observe(spent); + functionSetupCounter.inc(); + + return spent; + } - const buf = JSON.stringify(Object.assign({ - client: config.metric.client, - metric: this.metric, - time: spent, - }, options || {})); + observeFunctionUpdate(status) { + const spent = (Date.now() - this.start) / 1000; + const normalizedStatusCode = normalizeStatusCode(status); - sender.send(buf, config.metric.udpPort, config.metric.udpHost, (err) => { - if (err) { - log.error('Failed to sent udp metric: %s', err.message); - } - }); + functionUpdateHistogram.labels(normalizedStatusCode).observe(spent); + functionUpdateCounter.labels(normalizedStatusCode).inc(); - return spent / 1000; + return spent; } } diff --git a/lib/domain/Pipeline.js b/lib/domain/Pipeline.js index 49a55a6..71114ff 100644 --- a/lib/domain/Pipeline.js +++ b/lib/domain/Pipeline.js @@ -3,18 +3,21 @@ const Metric = require('./Metric'); const { DefaultLogStorage } = require('./LogStorage'); const ErrorTracker = require('./ErrorTracker'); +const SpanConsoleWrapper = require('./SpanConsoleWrapper'); +const { reportError } = require('../support/tracing'); function codeFileName(namespace, codeId) { return `${namespace}/${codeId}.js`; } class Pipeline { - constructor(sandbox, req, steps) { + constructor(sandbox, req, steps, span) { this.sandbox = sandbox; this.req = req; this.steps = steps; this.previousResult = null; - this.totalMetric = new Metric('pipeline-run'); + + this.span = span; this.breadcrumbs = []; } run() { @@ -27,16 +30,25 @@ class Pipeline { const metric = new Metric('function-run'); const filename = codeFileName(step.namespace, step.id); const logStorage = new DefaultLogStorage(step.namespace, step.id, this.req); + const span = this.span.tracer().startSpan('run function', { + childOf: this.span, + tags: { + 'function.namespace': step.namespace, + 'function.id': step.id, + }, + }); const options = { - console: logStorage.console, + console: new SpanConsoleWrapper(logStorage.console, span), env: step.env, + span, }; try { const result = await this.sandbox.runScript(step.script, this.req, options); - const spent = metric.finish({ - filename, + const spent = metric.observeFunctionRun({ + namespace: step.namespace, + id: step.id, status: result.status, }); @@ -49,6 +61,7 @@ class Pipeline { this.previousResult = result; this.pushBreadcrumb(filename, result); if (result.status === 304) { + span.log({ message: 'Not modified' }); if (previousResult) { result.status = previousResult.status; result.body = deepcopy(previousResult.body); @@ -59,9 +72,11 @@ class Pipeline { result.body.namespace = step.namespace; result.body.functionId = step.id; + span.finish(); return result; } + span.finish(); if (this.steps.length === 0) { return result; } @@ -69,23 +84,22 @@ class Pipeline { return this.runStep(); } catch (err) { const status = err.statusCode || 500; - - const spent = metric.finish({ - filename, + const spent = metric.observeFunctionRun({ + namespace: step.namespace, + id: step.id, status, - error: err.message, }); logStorage.console.error(`Failed to run function: ${err.message}, ${spent} seconds`); logStorage.console.error(err.stack); + reportError(span, err); const logResult = logStorage.flush({ status, requestTime: spent, }); - const { namespaceSettings } = step; - const { sentryDSN } = namespaceSettings || {}; + const { sentryDSN } = step; const extra = Object.assign({ body: this.req.body }, logResult || {}); const errTracker = new ErrorTracker({ diff --git a/lib/domain/SpanConsoleWrapper.js b/lib/domain/SpanConsoleWrapper.js new file mode 100644 index 0000000..92c5e3a --- /dev/null +++ b/lib/domain/SpanConsoleWrapper.js @@ -0,0 +1,30 @@ +const { Console } = require('console'); +const { Writable } = require('stream'); + +class SpanConsoleStream extends Writable { + constructor(level, console, span) { + super(); + this.level = level; + this.console = console; + this.span = span; + } + + _write(chunk, encoding, done) { + const message = chunk.toString().trim(); + this.console[this.level](message); + this.span.log({ level: this.level, message }); + done(); + } +} + + +class SpanConsoleWrapper extends Console { + constructor(console, span) { + super( + new SpanConsoleStream('info', console, span), + new SpanConsoleStream('error', console, span), + ); + } +} + +module.exports = SpanConsoleWrapper; diff --git a/lib/domain/getStorage.js b/lib/domain/getStorage.js new file mode 100644 index 0000000..212ce90 --- /dev/null +++ b/lib/domain/getStorage.js @@ -0,0 +1,12 @@ +const StorageRedis = require('../domain/storage/redis'); +const StorageInMemory = require('../domain/storage/InMemory'); +const config = require('../support/config'); + +const DEFAULT_STORAGES = { + redis: StorageRedis, + inmemory: StorageInMemory, +}; + +const getStorage = DEFAULT_STORAGES[config.storageName]; + +module.exports = getStorage; diff --git a/lib/domain/schemas.js b/lib/domain/schemas.js index b17dc65..3ba31be 100644 --- a/lib/domain/schemas.js +++ b/lib/domain/schemas.js @@ -47,6 +47,18 @@ const functionLinks = [ href: '/functions/{namespace}/{id}/env/{envVar}', method: 'DELETE', }, + { + rel: 'namespace', + href: '/namespaces/{namespace}', + }, + { + rel: 'update-namespace', + href: '/namespaces/{namespace}', + method: 'PUT', + schema: { + type: 'object', + }, + }, ]; const functionsItemLinks = [ @@ -128,6 +140,14 @@ const functionItem = { title: 'Namespace', readOnly: true, }, + provider: { + type: 'string', + title: 'Provider', + }, + projectId: { + type: 'string', + title: 'ProjectId', + }, id: { type: 'string', title: 'ID', diff --git a/lib/domain/status.js b/lib/domain/status.js index 2b91c03..b3e1461 100644 --- a/lib/domain/status.js +++ b/lib/domain/status.js @@ -1,26 +1,55 @@ +const ErrorTracker = require('./ErrorTracker'); + + class Status { constructor(storage) { this.storage = storage; } async run() { - const startTime = new Date().getTime(); + this.services = []; + this.startTime = new Date().getTime(); + try { const reply = await this.storage.ping(); - return { + this.push({ name: this.storage.name, status: 'WORKING', message: reply.toString(), - time: (new Date().getTime() - startTime), - }; + }); } catch (error) { - return { + this.push({ name: this.storage.name, status: 'FAILED', message: error.toString(), - time: (new Date().getTime() - startTime), - }; + }); } + + try { + const reply = await ErrorTracker.ping(); + this.push({ + name: ErrorTracker.name, + status: 'WORKING', + message: reply, + }); + } catch (error) { + this.push({ + name: ErrorTracker.name, + status: 'FAILED', + message: error.toString(), + }); + } + + return this.services; + } + + push({ name, status, message }) { + this.services.push({ + name, + status, + message, + time: (new Date().getTime() - this.startTime), + }); } } diff --git a/lib/domain/storage.js b/lib/domain/storage.js index acfda93..a77c576 100644 --- a/lib/domain/storage.js +++ b/lib/domain/storage.js @@ -5,8 +5,8 @@ /* eslint class-methods-use-this: [ 'error', { "exceptMethods": ['ping', - 'listNamespaces', - 'postCode', 'putCode', 'getCode', 'deleteCode', + 'listNamespaces', 'search', + 'putCode', 'getCode', 'deleteCode', 'getCodeByCache', 'getCodesByCache', 'putCodeEnviromentVariable', 'deleteCodeEnviromentVariable', @@ -21,12 +21,24 @@ class Storage { this.name = name; } + static getSentryByEnvOrNamespace(code) { + const { namespaceSettings, env } = code; + if (env && env.sentryDSN) return env.sentryDSN; + + if (namespaceSettings && namespaceSettings.sentryDSN) { + return namespaceSettings.sentryDSN; + } + + return null; + } + ping() { throw ERR_UNIMPLEMENTED_METHOD; } listNamespaces() { throw ERR_UNIMPLEMENTED_METHOD; } - postCode() { throw ERR_UNIMPLEMENTED_METHOD; } + search() { throw ERR_UNIMPLEMENTED_METHOD; } putCode() { throw ERR_UNIMPLEMENTED_METHOD; } getCode() { throw ERR_UNIMPLEMENTED_METHOD; } deleteCode() { throw ERR_UNIMPLEMENTED_METHOD; } + getProvider() { throw ERR_UNIMPLEMENTED_METHOD; } getCodeByCache() { throw ERR_UNIMPLEMENTED_METHOD; } getCodesByCache() { throw ERR_UNIMPLEMENTED_METHOD; } putCodeEnviromentVariable() { throw ERR_UNIMPLEMENTED_METHOD; } diff --git a/lib/domain/storage/InMemory.js b/lib/domain/storage/InMemory.js new file mode 100644 index 0000000..6185409 --- /dev/null +++ b/lib/domain/storage/InMemory.js @@ -0,0 +1,252 @@ +const Storage = require('../storage'); +const uuidV4 = require('uuid/v4'); +const Paginator = require('../paginator'); + +const ERR_FUNCTION_NOT_FOUND = new Error('Function not found'); +const ERR_ENV_NOT_FOUND = new Error('Env variable not found'); + +ERR_FUNCTION_NOT_FOUND.statusCode = 404; +ERR_ENV_NOT_FOUND.statusCode = 404; + +function executorKey(namespace, codeId) { + return `executor:${namespace}/${codeId}`; +} + +function storageKey(namespace, codeId) { + return `code:${namespace}/${codeId}`; +} + +function functionInMemoryKey(namespace, id) { + return `${namespace}:${id}`; +} + +function getFunctionInMemoryKey(functionStorageKey) { + const items = functionStorageKey.split(':'); + return { + namespace: items[0], + id: items[1], + }; +} + +async function getMultiCodes(storage, codes, preCache) { + const keys = codes.map(({ namespace, id }) => storageKey(namespace, id)); + + return keys.map((key) => { + if (key in storage.storage) { + return preCache(storage.storage[key]); + } + return null; + }); +} + +class StorageInMemory extends Storage { + + constructor() { + super('InMemory'); + this.storage = {}; + this.namespaces = {}; + this.rangeNamespaces = []; + } + + async putCode(namespace, id, code) { + const key = storageKey(namespace, id); + const storage = this.storage[key]; + const updated = new Date().toISOString(); + const data = { + id, + namespace, + created: (storage && storage.created) ? storage.created : updated, + versionID: uuidV4(), + updated, + code: (storage && storage.code) ? storage.code : null, + provider: code.provider || null + }; + const functionCode = (storage && storage.code) ? storage.code : code; + + if (functionCode == null) { + data.created = data.updated; + } + + if (code.code) { + data.code = code.code; + data.hash = code.hash; + } + + if (code.env) { + data.env = JSON.stringify(code.env); + } + + this.storage[key] = data; + this.setNamespaceMember(namespace, id); + + return 'OK'; + } + + setNamespaceMember(namespace, id) { + const key = functionInMemoryKey(namespace, id); + if (!this.rangeNamespaces.includes(key)) { + this.rangeNamespaces.push(key); + } + } + + + + async getCode(namespace, id) { + const key = storageKey(namespace, id); + + const data = this.storage[key]; + if (!data || !data.code) { + return null; + } + + const namespaceSettings = await this.getNamespace(namespace); + if (namespaceSettings) { + delete namespaceSettings.namespace; + } + const result = { + id, + namespace, + code: data.code, + hash: data.hash, + created: data.created, + updated: data.updated, + namespaceSettings, + versionID: data.versionID || null, + provider: data.provider || null, + + }; + + if (data.env) { + result.env = JSON.parse(data.env); + } + + result.sentryDSN = Storage.getSentryByEnvOrNamespace(result); + + return result; + } + + async getProvider(namespace, id) { + const { provider } = await this.getCode(namespace, id) + return provider; + } + + async deleteCode(namespace, id) { + const key = storageKey(namespace, id); + delete this.storage[key]; + return 1; + } + + async getCodeByCache(namespace, id, { preCache }) { + const item = await this.getCode(namespace, id); + return preCache(item); + } + + async listNamespaces(page = 1, perPage = 10) { + const total = this.rangeNamespaces.length; + const paginator = new Paginator(page, perPage, total); + + if (!paginator.isValid) { + throw new Error(paginator.error); + } + + const result = { + items: this.rangeNamespaces.map(namespace => getFunctionInMemoryKey(namespace)), + page: paginator.page, + perPage: paginator.perPage, + }; + + if (paginator.previousPage) { + result.previousPage = paginator.previousPage; + } + + if (paginator.nextPage) { + result.nextPage = paginator.nextPage; + } + + return result; + } + + async search(namespace, id, page = 1, perPage = 10) { + const total = this.rangeNamespaces.length; + const paginator = new Paginator(page, perPage, total); + + if (!paginator.isValid) { + throw new Error(paginator.error); + } + + const functionKey = functionInMemoryKey(namespace, id || ''); + const items = []; + this.rangeNamespaces.forEach((key) => { + if (key.includes(functionKey)) { + items.push(getFunctionInMemoryKey(key)); + } + }); + + const result = { + items, + page: paginator.page, + perPage: paginator.perPage, + }; + + if (paginator.previousPage) { + result.previousPage = paginator.previousPage; + } + + if (paginator.nextPage) { + result.nextPage = paginator.nextPage; + } + + return result; + } + + async getNamespace(namespace) { + return this.namespaces[namespace] || null; + } + + putNamespace(namespace, data) { + this.namespaces[namespace] = data; + } + + deleteNamespace(namespace) { + delete this.namespaces[namespace]; + } + + async deleteCodeEnviromentVariable(namespace, id, env) { + const code = await this.getCode(namespace, id); + + if (!code) { + throw ERR_FUNCTION_NOT_FOUND; + } + + if (!code.env || !code.env[env]) { + throw ERR_ENV_NOT_FOUND; + } + + delete code.env[env]; + + return this.putCode(namespace, id, { env: code.env }); + } + + async putCodeEnviromentVariable(namespace, id, env, value) { + const code = await this.getCode(namespace, id); + + if (!code) { + throw ERR_FUNCTION_NOT_FOUND; + } + + if (!code.env) { + code.env = {}; + } + + code.env[env] = value; + + return this.putCode(namespace, id, { env: code.env }); + } + + async getCodesByCache(codes, { preCache }) { + return Promise.all(await getMultiCodes(this, codes, preCache)); + } + +} + +module.exports = StorageInMemory; diff --git a/lib/domain/storage/redis.js b/lib/domain/storage/redis.js index 37fb0a4..43d5f65 100644 --- a/lib/domain/storage/redis.js +++ b/lib/domain/storage/redis.js @@ -14,6 +14,10 @@ const ERR_ENV_NOT_FOUND = new Error('Env variable not found'); ERR_FUNCTION_NOT_FOUND.statusCode = 404; ERR_ENV_NOT_FOUND.statusCode = 404; +function executorKey(namespace, codeId) { + return `executor:${namespace}/${codeId}`; +} + function redisKey(namespace, codeId) { return `code:${namespace}/${codeId}`; } @@ -22,6 +26,18 @@ function namespaceRedisKey(namespace) { return `namespace:${namespace}`; } +function functionRedisKey(namespace, id) { + return `${namespace}:${id}`; +} + +function getFunctionRedisKey(functionKey) { + const items = functionKey.split(':'); + return { + namespace: items[0], + id: items[1], + }; +} + async function getCodeAndPopulateCache(storage, namespace, id, preCache) { log.info('Get code from database, namespace:', namespace, 'codeId:', id, 'and store on cache'); @@ -79,7 +95,7 @@ class StorageRedis extends Storage { enableReadyCheck: true, dropBufferSupport: true, enableOfflineQueue: this.options.enableOfflineQueue, - connectTimeout: 1000, + connectTimeout: config.redisConnectionTimeout, keyPrefix: this.options.keyPrefix, }; @@ -126,20 +142,11 @@ class StorageRedis extends Storage { throw new Error(paginator.error); } - const items = await this.client.zrange('namespaces', paginator.start, paginator.stop); - const list = []; - - for (let item of items) { - item = item.split(':'); - - list.push({ - namespace: item[0], - id: item[1], - }); - } + const keys = await this.client.zrange('namespaces', paginator.start, paginator.stop); + const items = keys.map(key => getFunctionRedisKey(key)); const result = { - items: list, + items, page: paginator.page, perPage: paginator.perPage, }; @@ -155,39 +162,51 @@ class StorageRedis extends Storage { return result; } - setNamespaceMember(namespace, id) { - return this.client.zadd('namespaces', 0, `${namespace}:${id}`); - } + async search(namespace, id, page = 1, perPage = 10) { + const total = await this.client.zcount('namespaces', '-inf', '+inf'); - deleteNamespaceMember(namespace, id) { - return this.client.zrem('namespaces', 0, `${namespace}:${id}`); - } + const paginator = new Paginator(page, perPage, total); - postCode(namespace, id, code) { - const key = redisKey(namespace, id); - const pipeline = this.client.pipeline(); - const created = new Date().toISOString(); + if (!paginator.isValid) { + throw new Error(paginator.error); + } - pipeline.hsetnx(key, 'code', code.code); - pipeline.hsetnx(key, 'hash', code.hash); - pipeline.hsetnx(key, 'versionID', uuidV4()); - pipeline.hsetnx(key, 'created', created); - pipeline.hsetnx(key, 'updated', created); + const minRange = `[${functionRedisKey(namespace, id || '*')}`; + const maxRange = `[${functionRedisKey(namespace, id || '\xff')}`; + const keys = await this.client.zrangebylex( + 'namespaces', + minRange, + maxRange, + 'limit', + paginator.start, + paginator.perPage + ); - if (code.env) { - pipeline.hsetnx(key, 'env', code.env); + const items = keys.map(key => getFunctionRedisKey(key)); + + const result = { + items, + page: paginator.page, + perPage: paginator.perPage, + }; + + if (paginator.previousPage) { + result.previousPage = paginator.previousPage; } - return pipeline.exec((err, results) => { - const codeResult = results[0][1]; - const hashResult = results[1][1]; + if (paginator.nextPage) { + result.nextPage = paginator.nextPage; + } - // Only save namespace and its member - // when code and hash don't exist - if (codeResult === 1 && hashResult === 1) { - this.setNamespaceMember(namespace, id); - } - }); + return result; + } + + setNamespaceMember(namespace, id) { + return this.client.zadd('namespaces', 0, functionRedisKey(namespace, id)); + } + + deleteNamespaceMember(namespace, id) { + return this.client.zrem('namespaces', 0, functionRedisKey(namespace, id)); } async putCode(namespace, id, code) { @@ -204,6 +223,8 @@ class StorageRedis extends Storage { data.hash = code.hash; } + data.provider = code.provider || null + if (code.env) { data.env = JSON.stringify(code.env); } @@ -239,6 +260,8 @@ class StorageRedis extends Storage { result.env = JSON.parse(data.env); } + result.sentryDSN = Storage.getSentryByEnvOrNamespace(result); + return result; } @@ -250,6 +273,11 @@ class StorageRedis extends Storage { return this.client.del(key); } + async getProvider(namespace, id) { + const { provider } = this.getCode(namespace, id) + return provider; + } + async getCodeByCache(namespace, id, { preCache }) { const key = redisKey(namespace, id); const versionID = await this.client.hget(key, 'versionID'); @@ -312,7 +340,7 @@ class StorageRedis extends Storage { async checkConnectionLeak() { const timeoutID = setTimeout(() => { log.error('Redis connection leak detected'); - new Metric('redis-connection-leak').finish(); + Metric.observeRedisLeak(); this.worker.disconnect(); setTimeout(() => { diff --git a/lib/http/SchemaResponse.js b/lib/http/SchemaResponse.js index c2abed1..fcd5fbf 100644 --- a/lib/http/SchemaResponse.js +++ b/lib/http/SchemaResponse.js @@ -1,11 +1,25 @@ +const config = require('../support/config'); + class SchemaResponse { constructor(functionsRequest, res, schemaName) { this.functionsRequest = functionsRequest; this.res = res; this.schemaName = schemaName; + this.notAllowedFields = config.responseNotAllowedFields; + } + + removeNotAllowedFields(data) { + const { env } = data; + if(env){ + const fieldsToRemove = Object.keys(env).filter(field => this.notAllowedFields.includes(field)); + for (const field of fieldsToRemove) { + delete data.env[field]; + } + } } json(data) { + this.removeNotAllowedFields(data); const schemeAndAuthority = this.functionsRequest.schemeAndAuthority(); this.res.set('Content-Type', `application/json; charset=utf-8; profile=${schemeAndAuthority}/_schemas/${this.schemaName}`); this.res.end(JSON.stringify(data)); diff --git a/lib/http/routers/DebugRouter.js b/lib/http/routers/DebugRouter.js index 17a176e..4f50559 100644 --- a/lib/http/routers/DebugRouter.js +++ b/lib/http/routers/DebugRouter.js @@ -12,7 +12,7 @@ function socketStats(sockets) { })); } -router.get('/http_stats', (req, res) => { +router.get('/http_stats', (req, res, next) => { res.json({ http: { sockets: socketStats(http.globalAgent.sockets), @@ -23,6 +23,7 @@ router.get('/http_stats', (req, res) => { freeSockets: socketStats(https.globalAgent.freeSockets), }, }); + next(); }); module.exports = router; diff --git a/lib/http/routers/FunctionsRouter.js b/lib/http/routers/FunctionsRouter.js index ec8985a..27a38f7 100644 --- a/lib/http/routers/FunctionsRouter.js +++ b/lib/http/routers/FunctionsRouter.js @@ -12,28 +12,38 @@ const { StdoutLogStorage, DefaultLogStorage } = require('../../domain/LogStorage const FunctionsRequest = require('../FunctionsRequest'); const Metric = require('../../domain/Metric'); const SchemaResponse = require('../SchemaResponse'); +const { FunctionProviderFactory } = require('../../domain/FunctionProvider'); + const router = new Router(); const { bodyParserLimit } = require('../../support/config'); - +const { reportError } = require('../../support/tracing'); +const { RecordOtelError } = require('../../support/opentelemetry') function codeFileName(namespace, codeId) { return `${namespace}/${codeId}.js`; } -router.get('/', async (req, res) => { +router.get('/', async (req, res, next) => { const memoryStorage = req.app.get('memoryStorage'); const page = parseInt(req.query.page || '1', 10); const perPage = parseInt(req.query.perPage || '10', 10); + const { namespace, id } = req.query; const functionsRequest = new FunctionsRequest(req); try { - const list = await memoryStorage.listNamespaces(page, perPage); + let list = {}; + if (namespace) { + list = await memoryStorage.search(namespace, id, page, perPage); + } else { + list = await memoryStorage.listNamespaces(page, perPage); + } new SchemaResponse(functionsRequest, res, 'functions/list').json(list); } catch (err) { log.error(`Error listing namespaces and its functions: ${err}`); res.status(500).json({ error: err.message }); } + next(); }); router.all('/:namespace/:id*', (req, res, next) => { @@ -41,74 +51,19 @@ router.all('/:namespace/:id*', (req, res, next) => { next(); }); -router.post('/:namespace/:id', bodyParser.json({ limit: bodyParserLimit }), async (req, res) => { - const validationResult = new Validator().validate(req.body, schemas['functions/item']); - const memoryStorage = req.app.get('memoryStorage'); - - if (!validationResult.valid) { - const error = 'Invalid instance'; - const details = validationResult.errors.map(e => e.toString()); - - res.status(400).json({ error, details }); - return; - } - - const namespace = req.params.namespace; - const id = req.params.id; - const { - code, - env, - } = req.body; - const sandbox = req.app.get('sandbox'); - const filename = codeFileName(namespace, id); - const invalid = sandbox.testSyntaxError(filename, code, { - console: new StdoutLogStorage(namespace, id).console, - }); - - if (invalid) { - req.log.error(`Failed to post code: ${invalid.error}`); - res.status(400).json(invalid); - return; - } - - const hash = crypto.createHash('sha1').update(code).digest('hex'); - const data = { id, code, hash }; - - if (env) { - data.env = env; - } - - try { - const result = await memoryStorage.postCode(namespace, id, data); - const codeResult = result[0][1]; - const hashResult = result[1][1]; - - // When code and hash are already saved - // we respond with a 400 - Bad Request - if (codeResult === 0 || hashResult === 0) { - res.status(400).json({ error: `The key ${namespace}:${id} already exists` }); - return; - } - - res.set({ ETag: data.hash }); - - new SchemaResponse(new FunctionsRequest(req), res, 'functions/item').json(data); - } catch (err) { - req.log.error(`${err}`); - req.log.error(`${err.stack}`); - res.status(500).json({ error: err.message }); - } -}); - +router.put('/:namespace/:id', bodyParser.json({ limit: bodyParserLimit }), async (req, res, next) => { + const functionProvider = req.headers['x-bs-function-provider'] + const isExternalFunctionProvider = !functionProvider || functionProvider != "sandbox" -router.put('/:namespace/:id', bodyParser.json({ limit: bodyParserLimit }), async (req, res) => { const validationResult = new Validator().validate(req.body, schemas['functions/item']); const memoryStorage = req.app.get('memoryStorage'); + const metric = new Metric('function-update'); if (!validationResult.valid) { const error = 'Invalid instance'; const details = validationResult.errors.map(e => e.toString()); + metric.observeFunctionUpdate(400); res.status(400).json({ error, details }); return; } @@ -118,23 +73,25 @@ router.put('/:namespace/:id', bodyParser.json({ limit: bodyParserLimit }), async } = req.params; const { code, - env, + env } = req.body; const filename = codeFileName(namespace, id); const sandbox = req.app.get('sandbox'); - const invalid = sandbox.testSyntaxError(filename, code, { - console: new StdoutLogStorage(namespace, id).console, - }); - if (invalid) { - req.log.error(`Failed to post code: ${invalid.error}`); - res.status(400).json(invalid); - return; + if(!isExternalFunctionProvider){ + const invalid = sandbox.testSyntaxError(filename, code, { + console: new StdoutLogStorage(namespace, id).console, + }); + if (invalid) { + req.log.error(`Failed to post code: ${invalid.error}`); + metric.observeFunctionUpdate(400); + res.status(400).json(invalid); + return; + } } const hash = crypto.createHash('sha1').update(code).digest('hex'); - const data = { id, code, hash }; - + const data = { id, code, hash, provider: functionProvider }; if (env) { data.env = env; } @@ -144,14 +101,18 @@ router.put('/:namespace/:id', bodyParser.json({ limit: bodyParserLimit }), async res.set({ ETag: data.hash }); const functionsRequest = new FunctionsRequest(req); + metric.observeFunctionUpdate(200); new SchemaResponse(functionsRequest, res, 'functions/item').json(data); } catch (err) { log.error(`[${namespace}:${id}] ${err}`); + metric.observeFunctionUpdate(500); res.status(500).json({ error: err.message }); } + + next(); }); -router.put('/:namespace/:id/env/:env', bodyParser.json({ strict: false, limit: bodyParserLimit }), async (req, res) => { +router.put('/:namespace/:id/env/:env', bodyParser.json({ strict: false, limit: bodyParserLimit }), async (req, res, next) => { const validationResult = new Validator().validate(req.body, schemas['functions/env']); const memoryStorage = req.app.get('memoryStorage'); @@ -177,9 +138,10 @@ router.put('/:namespace/:id/env/:env', bodyParser.json({ strict: false, limit: b log.error(`[${namespace}:${id}] Failed to set enviroment variable ${env}, error: ${err}`); res.status(err.statusCode || 500).json({ error: err.message }); } + next(); }); -router.delete('/:namespace/:id/env/:env', async (req, res) => { +router.delete('/:namespace/:id/env/:env', async (req, res, next) => { const { namespace, id, @@ -195,15 +157,19 @@ router.delete('/:namespace/:id/env/:env', async (req, res) => { log.error(`[${namespace}:${id}] Failed to unset enviroment variable ${env}, error: ${err}`); res.status(err.statusCode || 500).json({ error: err.message }); } + next(); }); -router.get('/:namespace/:id', async (req, res) => { +router.get('/:namespace/:id', async (req, res, next) => { const { namespace, id, } = req.params; const memoryStorage = req.app.get('memoryStorage'); + const functionProvider = req.headers['x-bs-function-provider'] + const isExternalFunctionProvider = !functionProvider || functionProvider != "sandbox" + try { const code = await memoryStorage.getCode(namespace, id); if (!code) { @@ -213,7 +179,9 @@ router.get('/:namespace/:id', async (req, res) => { return; } - res.set({ ETag: code.hash }); + if(!isExternalFunctionProvider){ + res.set({ ETag: code.hash }); + } const functionsRequest = new FunctionsRequest(req); @@ -223,10 +191,10 @@ router.get('/:namespace/:id', async (req, res) => { req.log.error(`${err.stack}`); res.status(500).json({ error: err.message }); } + next(); }); - -router.delete('/:namespace/:id', async (req, res) => { +router.delete('/:namespace/:id', async (req, res, next) => { const namespace = req.params.namespace; const id = req.params.id; const memoryStorage = req.app.get('memoryStorage'); @@ -238,52 +206,46 @@ router.delete('/:namespace/:id', async (req, res) => { req.log.error(`Failed to delete code id: ${err}`); res.status(500).json({ error: err.message }); } + next(); }); -router.all('/:namespace/:id/run', bodyParser.json({ limit: bodyParserLimit }), async (req, res) => { +router.all('/:namespace/:id/run', bodyParser.json({ limit: bodyParserLimit }), async (req, res, next) => { const { namespace, id } = req.params; - const memoryStorage = req.app.get('memoryStorage'); - const sandbox = req.app.get('sandbox'); const filename = codeFileName(namespace, id); + req.params.filename = filename + const memoryStorage = req.app.get('memoryStorage') const metric = new Metric('function-run'); const logStorage = new DefaultLogStorage(namespace, id, req); + req.params.logStorage = logStorage + + const span = req.span.tracer().startSpan('run function', { + childOf: req.span, + tags: { + 'function.namespace': namespace, + 'function.id': id, + }, + }); + req.params.span = span - let code; try { - code = await memoryStorage.getCodeByCache(namespace, id, { - preCache: (preCode) => { - preCode.script = sandbox.compileCode(filename, preCode.code); - return preCode; - }, - }); + const providerId = await memoryStorage.getProvider(namespace, id); - if (!code) { - const error = new Error(`Code '${namespace}/${id}' is not found`); - error.statusCode = 404; - throw error; - } - } catch (err) { - res.status(err.statusCode || 500).json({ error: err.message }); - return; - } + const factory = new FunctionProviderFactory(); - try { - const options = { - console: logStorage.console, - env: code.env, - }; - const result = await sandbox.runScript(code.script, req, options); + const executor = factory.getFunctionProvider(providerId); + + const result = await executor.run(req); + + metric.observeFunctionSetup(); res.set(result.headers); res.status(result.status); res.json(result.body); + span.finish(); - const spent = metric.finish({ - filename, - status: result.status, - }); + const spent = metric.observeFunctionRun({ namespace, id, status: result.status }); logStorage.flush({ status: result.status, @@ -292,44 +254,51 @@ router.all('/:namespace/:id/run', bodyParser.json({ limit: bodyParserLimit }), a } catch (err) { logStorage.console.error(`Failed to run function: ${err}`); logStorage.console.error(err.stack); + reportError(span, err); + const status = err.statusCode || 500; res.status(status).json({ error: err.message }); - const spent = metric.finish({ - filename, - status, - error: err.message, - }); + const spent = metric.observeFunctionRun({ namespace, id, status }); const logResult = logStorage.flush({ status, requestTime: spent, }); - const { namespaceSettings } = code; - const { sentryDSN } = namespaceSettings || {}; - - const extra = Object.assign({ body: req.body }, logResult || {}); - const errTracker = new ErrorTracker({ - sentryDSN, - filename, - extra, - tags: { codeHash: code.hash }, - code: code.code, - }); - errTracker.notify(err); + // const { sentryDSN } = code; + + // const extra = Object.assign({ body: req.body }, logResult || {}); + // const errTracker = new ErrorTracker({ + // sentryDSN, + // filename, + // extra, + // // tags: { codeHash: code.hash }, + // // code: code.code, + // }); + // errTracker.notify(err); + // RecordOtelError(err) } }); -router.put('/pipeline', bodyParser.json({ limit: bodyParserLimit }), async (req, res) => { +router.put('/pipeline', bodyParser.json({ limit: bodyParserLimit }), async (req, res, next) => { const memoryStorage = req.app.get('memoryStorage'); const sandbox = req.app.get('sandbox'); let { steps } = req.query; + const span = req.span.tracer().startSpan('run pipeline', { + childOf: req.span, + tags: { + 'function.steps': Array.isArray(steps) ? steps.join(', ') : '', + }, + }); + if (!steps) { - res.status(400).json({ error: 'Pass step by querystring is required' }); + const err = new Error('Pass step by querystring is required'); + reportError(span, err); + res.status(400).json({ error: err.message }); return; } steps = steps.map((step) => { @@ -337,6 +306,8 @@ router.put('/pipeline', bodyParser.json({ limit: bodyParserLimit }), async (req, return { namespace, id }; }); + const metric = new Metric('pipeline-run'); + try { const codes = await memoryStorage.getCodesByCache(steps, { preCache: (code) => { @@ -351,19 +322,26 @@ router.put('/pipeline', bodyParser.json({ limit: bodyParserLimit }), async (req, const { namespace, id } = steps[i]; const e = new Error(`Code '${namespace}/${id}' is not found`); e.statusCode = 404; + reportError(span, e); throw e; } } - const result = await new Pipeline(sandbox, req, codes).run(); + const result = await new Pipeline(sandbox, req, codes, span).run(); res.set(result.headers); res.status(result.status); + span.finish(); + metric.observePipelineRun(result.status); res.json(result.body); } catch (err) { + reportError(span, err); + RecordOtelError(err) const status = err.statusCode || 500; + metric.observePipelineRun(status); res.status(status).json({ error: err.message }); } + next(); }); module.exports = router; diff --git a/lib/http/routers/HealthcheckRouter.js b/lib/http/routers/HealthcheckRouter.js index 06ea9b3..af26849 100644 --- a/lib/http/routers/HealthcheckRouter.js +++ b/lib/http/routers/HealthcheckRouter.js @@ -4,7 +4,7 @@ const log = require('../../support/log'); const router = new Router(); -router.get('/', async (req, res) => { +router.get('/', async (req, res, next) => { const memoryStorage = req.app.get('memoryStorage'); try { await memoryStorage.ping(); @@ -13,6 +13,7 @@ router.get('/', async (req, res) => { log.error(err); res.status(500).send(`Error: ${err.message}`); } + next(); }); module.exports = router; diff --git a/lib/http/routers/MetricsRouter.js b/lib/http/routers/MetricsRouter.js new file mode 100644 index 0000000..3bd3f7e --- /dev/null +++ b/lib/http/routers/MetricsRouter.js @@ -0,0 +1,21 @@ +const Router = require('express').Router; +const prometheusClient = require('prom-client'); +const log = require('../../support/log'); + +const router = new Router(); +const aggregatorRegistry = new prometheusClient.AggregatorRegistry(); + +router.get('/', (req, res) => { + aggregatorRegistry.clusterMetrics((err, metrics) => { + if (err) { + log.error(err); + res.send(`Error: ${err}`); + res.status(500); + return; + } + res.set('Content-Type', aggregatorRegistry.contentType); + res.send(metrics); + }); +}); + +module.exports = router; diff --git a/lib/http/routers/NamespacesRouter.js b/lib/http/routers/NamespacesRouter.js index 994e6ee..01a7d82 100644 --- a/lib/http/routers/NamespacesRouter.js +++ b/lib/http/routers/NamespacesRouter.js @@ -10,7 +10,7 @@ const router = new Router(); const { bodyParserLimit } = require('../../support/config'); const log = require('../../support/log'); -router.put('/:namespace', bodyParser.json({ limit: bodyParserLimit }), async (req, res) => { +router.put('/:namespace', bodyParser.json({ limit: bodyParserLimit }), async (req, res, next) => { try { const validationResult = new Validator().validate(req.body, schemas['namespaces/item']); const memoryStorage = req.app.get('memoryStorage'); @@ -37,9 +37,10 @@ router.put('/:namespace', bodyParser.json({ limit: bodyParserLimit }), async (re log.error(err.stack); res.status(500).json({ error: err.message }); } + next(); }); -router.get('/:namespace', async (req, res) => { +router.get('/:namespace', async (req, res, next) => { const { namespace, } = req.params; @@ -61,10 +62,11 @@ router.get('/:namespace', async (req, res) => { log.error(err.stack); res.status(500).json({ error: err.message }); } + next(); }); -router.delete('/:namespace', async (req, res) => { +router.delete('/:namespace', async (req, res, next) => { const namespace = req.params.namespace; const memoryStorage = req.app.get('memoryStorage'); @@ -76,6 +78,7 @@ router.delete('/:namespace', async (req, res) => { log.error(err.stack); res.status(500).json({ error: err.message }); } + next(); }); module.exports = router; diff --git a/lib/http/routers/SchemasRouter.js b/lib/http/routers/SchemasRouter.js index e0ee2f3..995bc50 100644 --- a/lib/http/routers/SchemasRouter.js +++ b/lib/http/routers/SchemasRouter.js @@ -6,7 +6,7 @@ const FunctionsRequest = require('../FunctionsRequest'); const router = new Router(); -router.get('/*', (req, res) => { +router.get('/*', (req, res, next) => { const name = req.params[0]; if (schemas[name]) { const schema = schemas[name]; @@ -16,6 +16,7 @@ router.get('/*', (req, res) => { } else { res.status(404).json({ error: 'Schema not found' }); } + next(); }); module.exports = router; diff --git a/lib/http/routers/StatusRouter.js b/lib/http/routers/StatusRouter.js index 47bdc30..ed3cc10 100644 --- a/lib/http/routers/StatusRouter.js +++ b/lib/http/routers/StatusRouter.js @@ -4,18 +4,20 @@ const Status = require('../../domain/status'); const router = new Router(); -router.get('/', async (req, res) => { +router.get('/', async (req, res, next) => { const memoryStorage = req.app.get('memoryStorage'); - const status = new Status(memoryStorage); - const output = await status.run(); - const statusCode = output.status === 'WORKING' ? 200 : 500; + const services = await new Status(memoryStorage).run(); + const failedServices = services.filter(s => s.status !== 'WORKING'); - if (statusCode === 500) { - log.error(output.message); + let statusCode = 200; + + for (const failedService of failedServices) { + statusCode = 500; + log.error(failedService.message); } - res.status(statusCode).json({ - services: [output], - }); + + res.status(statusCode).json({ services }); + next(); }); module.exports = router; diff --git a/lib/http/routes.js b/lib/http/routes.js index f7387ed..da8fae5 100644 --- a/lib/http/routes.js +++ b/lib/http/routes.js @@ -1,5 +1,6 @@ const express = require('express'); const morgan = require('morgan'); +const expressOpentracing = require('express-opentracing'); const Sandbox = require('@globocom/backstage-functions-sandbox'); @@ -10,12 +11,18 @@ const StatusRouter = require('./routers/StatusRouter'); const DebugRouter = require('./routers/DebugRouter'); const NamespacesRouter = require('./routers/NamespacesRouter'); const FunctionsRouter = require('./routers/FunctionsRouter'); -const RedisStorage = require('../domain/storage/redis'); + const parseExposeEnv = require('../support/parseExposeEnv'); + const config = require('../support/config'); +const { StartSpanMiddleware, FinalizeSpanMiddleware } = require('../support/opentelemetry'); + +const { tracer } = require('../support/tracing'); const FunctionsRequest = require('./FunctionsRequest'); +const Storage = require('../domain/getStorage'); + morgan.token('response-sectime', (req, res) => { /* eslint no-underscore-dangle: ["error", { "allow": ["_header", "_startAt"] }] */ if (!res._header || !req._startAt) { @@ -25,14 +32,14 @@ morgan.token('response-sectime', (req, res) => { const secs = diff[0] + (diff[1] * 1e-9); return secs.toFixed(3); }); - const app = express(); - +const traceEngine = config.trace.engine app.use(morgan(config.log.morganFormat)); +app.use(expressOpentracing.default({ tracer })); + app.disable('x-powered-by'); app.enable('trust proxy'); - -app.set('memoryStorage', new RedisStorage()); +app.set('memoryStorage', new Storage()); app.set('sandbox', new Sandbox({ env: parseExposeEnv(), globalModules: config.defaultGlobalModules, @@ -42,13 +49,16 @@ app.set('sandbox', new Sandbox({ app.get('/', (req, res) => { const backstageRequest = new FunctionsRequest(req); - new SchemaResponse(backstageRequest, res, 'root') .json({ name: 'Backstage functions', }); }); +if (traceEngine.toLowerCase() === 'opentelemetry') { + app.use(StartSpanMiddleware); +} + app.use('/healthcheck', HealthcheckRouter); app.use('/status', StatusRouter); app.use('/_debug', DebugRouter); @@ -56,5 +66,8 @@ app.use('/_schemas', SchemasRouter); app.use('/functions', FunctionsRouter); app.use('/namespaces', NamespacesRouter); +if (traceEngine.toLowerCase() === 'opentelemetry') { + app.use(FinalizeSpanMiddleware); +} module.exports = app; diff --git a/lib/support/config.js b/lib/support/config.js index 24d9b0f..4e26128 100644 --- a/lib/support/config.js +++ b/lib/support/config.js @@ -7,10 +7,13 @@ const DEFAULT_GLOBAL_MODULES = [ 'async', 'request', 'uuid', + 'node-fetch', ]; module.exports = { + host: process.env.HOSTNAME || "localhost", port: ConfigDiscovery.getInt('PORT', 8100), + metricsPort: ConfigDiscovery.getInt('METRICS_PORT', 8101), useNodeCluster: ConfigDiscovery.getBool('USE_NODE_CLUSTER', true), numCPUs: ConfigDiscovery.getInt('NUM_CPUS', numCPUs), syncTimeout: ConfigDiscovery.getInt('CODE_SYNC_TIMEOUT', 100), @@ -18,6 +21,9 @@ module.exports = { redis: ConfigDiscovery.parseRedisOptions(), defaultGlobalModules: ConfigDiscovery.getList('DEFAULT_GLOBAL_MODULES', DEFAULT_GLOBAL_MODULES), bodyParserLimit: process.env.BODY_PARSER_LIMIT || '1mb', + redisConnectionTimeout: ConfigDiscovery.getInt('REDIS_CONNECTION_TIMEOUT', 2000), + responseNotAllowedFields: ConfigDiscovery.getList('RESPONSE_NOT_ALLOWED_FIELDS', ['CLIENT_SECRET']), + googleCloudCredentials: process.env.GOOGLE_CREDENTIALS || null, metric: { client: process.env.METRIC_CLIENT, udpHost: process.env.METRIC_UDP_HOST, @@ -25,15 +31,33 @@ module.exports = { }, log: { type: process.env.LOG_TYPE || 'local', - host: process.env.LOG_HOST || 'localhost', + hosts: ConfigDiscovery.getList('LOG_HOSTS', ['localhost']), port: ConfigDiscovery.getInt('LOG_PORT', 12201), fields: ConfigDiscovery.getObject('LOG_FIELDS'), fieldsFromHTTPHeaders: ConfigDiscovery.getObject('LOG_FIELDS_FROM_HTTP_HEADERS'), + maxFullMessage: ConfigDiscovery.getInt('LOG_MAX_FULL_MESSAGE', 3000), + maxChunkSize: ConfigDiscovery.getInt('LOG_MAX_CHUNK_SIZE', 32766), morganFormat: process.env.LOG_MONGAN_FORMAT || 'tiny', + format: process.env.LOG_APP_FORMAT || 'console', }, http: { keepAlive: ConfigDiscovery.getBool('HTTP_KEEP_ALIVE', false), useCertFile: ConfigDiscovery.getBool('FUNCTIONS_USE_SSL_CERT_FILE', false), certFile: process.env.SSL_CERT_FILE, }, + trace: { + engine: process.env.TRACE_ENGINE || 'opentracing', + otel: { + collector: { + host: process.env.OTEL_COLLECTOR_HOST || 'no-op', + port: process.env.OTEL_COLLECTOR_PORT || 55680, + }, + service: process.env.OTEL_EXPORTER_SERVICE, + }, + }, + + storageName: process.env.STORAGE || 'redis', + opentracingEngine: process.env.OPENTRACING_ENGINE || 'no-op', + opentracingService: ConfigDiscovery.getPossibleString(['OPENTRACING_SERVICE', 'TSURU_APPNAME'], 'functions'), + jaegerPropagation: process.env.JAEGER_PROPAGATION || 'jaeger', }; diff --git a/lib/support/log.js b/lib/support/log.js index 6565365..dd8b151 100644 --- a/lib/support/log.js +++ b/lib/support/log.js @@ -9,14 +9,21 @@ if (config.numCPUs === 1) { logLabel = undefined; } +const consoleConfig = { + colorize: true, + label: logLabel, + level: logLevel, + timestamp: false, +}; + +if (config.log.format.toLowerCase() === 'json') { + consoleConfig.json = true; + consoleConfig.stringify = obj => JSON.stringify(obj); +} + const logger = new Logger({ transports: [ - new Console({ - colorize: true, - label: logLabel, - level: logLevel, - timestamp: false, - }), + new Console(consoleConfig), ], }); diff --git a/lib/support/opentelemetry.js b/lib/support/opentelemetry.js new file mode 100644 index 0000000..55ccd03 --- /dev/null +++ b/lib/support/opentelemetry.js @@ -0,0 +1,74 @@ +const { BatchSpanProcessor } = require('@opentelemetry/tracing'); +const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http'); +const { ExpressInstrumentation } = require('@opentelemetry/instrumentation-express'); +const { registerInstrumentations } = require('@opentelemetry/instrumentation'); +const { CollectorTraceExporter } = require('@opentelemetry/exporter-collector-grpc'); +const { NodeTracerProvider } = require('@opentelemetry/node'); +const { IORedisInstrumentation } = require('@opentelemetry/instrumentation-ioredis') +const config = require('./config') + +const opentelemetry = require('@opentelemetry/api'); +const OtelConfig = config.trace.otel; +const HOST = config.host + +const collectorOptions = { + serviceName: OtelConfig.service, + url: `${OtelConfig.collector.host}:${OtelConfig.collector.port}`, + concurrencyLimit: 10 +} + +const provider = new NodeTracerProvider(); + +provider.resource = provider.resource.merge({ + attributes: { + "service.instance.id": HOST + } +}) + +const exporter = new CollectorTraceExporter(collectorOptions); +provider.addSpanProcessor(new BatchSpanProcessor(exporter, { + maxQueueSize: 1000, + scheduledDelayMillis: 30000, +})); + +registerInstrumentations({ + instrumentations: [ + new IORedisInstrumentation(), + new HttpInstrumentation({ responseHook: (span) => { + const { attributes: attrs = {} } = span; + span.updateName(`${attrs['http.method']} ${attrs['http.target']}`); + span.setAttribute('functions.route', attrs['http.route']); + span.setAttribute('functions.url', attrs['http.url']); + }, + ignoreOutgoingUrls: [/.*\/agent_listener/, /.*\/sampling/], + ignoreIncomingPaths: [/.*\/healthcheck/, /.*\/metrics/, /.*\/sampling/] + }), + new ExpressInstrumentation() + ], +}); + +provider.register(); +const tracer = opentelemetry.trace.getTracer(OtelConfig.service); + +function StartSpanMiddleware(req, res, next) { + const span = tracer.startSpan(req.path, { attributes: { + "http.request_id": req.headers["x-request-id"] + }}); + req.otelSpan = span; + next(); +} + +function FinalizeSpanMiddleware(req, res, next) { + const { otelSpan } = req; + if (otelSpan && otelSpan.end) otelSpan.end(); + next(); +} + +function RecordOtelError(err) { + const span = tracer.startSpan('Exception Throwed') + span.recordException(err.stack) + span.setStatus({code: opentelemetry.SpanStatusCode.ERROR }) + span.end() +} + +module.exports = { StartSpanMiddleware, FinalizeSpanMiddleware, RecordOtelError }; diff --git a/lib/support/tracing.js b/lib/support/tracing.js new file mode 100644 index 0000000..77bb2ff --- /dev/null +++ b/lib/support/tracing.js @@ -0,0 +1,43 @@ +const jaegerClient = require('jaeger-client'); +const opentracing = require('opentracing'); +const config = require('./config'); + +function setupTracer() { + if (config.opentracingEngine !== 'jaeger') { + // this is a no-op tracer + return new opentracing.Tracer(); + } + + const jaegerConfig = { + serviceName: config.opentracingService, + }; + const options = {}; + const tracer = jaegerClient.initTracerFromEnv(jaegerConfig, options); + + if (config.jaegerPropagation === 'b3') { + const httpCodec = new jaegerClient.ZipkinB3TextMapCodec({ urlEncoding: true }); + + tracer.registerInjector(opentracing.FORMAT_HTTP_HEADERS, httpCodec); + tracer.registerExtractor(opentracing.FORMAT_HTTP_HEADERS, httpCodec); + + const textCodec = new jaegerClient.ZipkinB3TextMapCodec({ urlEncoding: false }); + tracer.registerInjector(opentracing.FORMAT_TEXT_MAP, textCodec); + tracer.registerExtractor(opentracing.FORMAT_TEXT_MAP, textCodec); + } + return tracer; +} + +const tracer = setupTracer(); + +function reportError(span, err) { + span.setTag(opentracing.Tags.ERROR, true); + span.log({ + event: 'error', + message: err.message, + stack: err.stack, + 'error.object': err, + }); + span.finish(); +} + +module.exports = { tracer, reportError }; diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 521e727..934458e 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,18 +1,419 @@ { "name": "@globocom/backstage-functions", - "version": "0.1.0", + "version": "0.4.3", "lockfileVersion": 1, "requires": true, "dependencies": { "@globocom/backstage-functions-sandbox": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@globocom/backstage-functions-sandbox/-/backstage-functions-sandbox-0.3.2.tgz", - "integrity": "sha512-gh8uZp6MCDBo/4RZGkGopfCEKdOq5qCLpcIu2qd4/j1a0pR8d8Z6F//84xL7FdO68NSLpXFVd6WVFWqOFGCPlw==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@globocom/backstage-functions-sandbox/-/backstage-functions-sandbox-0.5.3.tgz", + "integrity": "sha512-+KNd1bM0QoqZ4UufHKe8NlZbahlx7lrLODSyHKDPS0669vEiWT/kxoRB6c/epRJms/Mf6yncmRqxH8nmNq1tyA==", + "requires": { + "once": "^1.4.0", + "stack-trace": "^0.0.9" + } + }, + "@grpc/grpc-js": { + "version": "1.3.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@grpc/grpc-js/-/grpc-js-1.3.0.tgz", + "integrity": "sha1-xv66rwDOf1O17FLHzz4qRyW4K8s=", + "requires": { + "@types/node": ">=12.12.47" + } + }, + "@grpc/proto-loader": { + "version": "0.6.1", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@grpc/proto-loader/-/proto-loader-0.6.1.tgz", + "integrity": "sha1-rWPox9KiOwF1x47rwm3t9rCvCws=", + "requires": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^6.10.0", + "yargs": "^16.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U=" + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha1-oCZe5lVHb8gHrqnfPfjfd4OAi08=", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/long/-/long-4.0.0.tgz", + "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=" + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha1-2v1PlVmnWFz7pSnGoKT3NIjr1MU=", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI=", + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha1-HIK/D2tqZur85+8w43b0mhJHf2Y=", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, + "@opentelemetry/api": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-0.18.1.tgz", + "integrity": "sha512-pKNxHe3AJ5T2N5G3AlT9gx6FyF5K2FS9ZNc+FipC+f1CpVF/EY+JHTJ749dnM2kWIgZTbDJFiGMuc0FYjNSCOg==" + }, + "@opentelemetry/api-metrics": { + "version": "0.19.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@opentelemetry/api-metrics/-/api-metrics-0.19.0.tgz", + "integrity": "sha1-O1lEzob0VRy/8a/cHQZK3xii22g=" + }, + "@opentelemetry/context-async-hooks": { + "version": "0.19.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@opentelemetry/context-async-hooks/-/context-async-hooks-0.19.0.tgz", + "integrity": "sha1-uVm2yIDIkU+TGlJwUdqGyzFx0Os=" + }, + "@opentelemetry/core": { + "version": "0.19.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@opentelemetry/core/-/core-0.19.0.tgz", + "integrity": "sha1-UBjhbR0wgdoGV0duWNnC3OfFEaI=", + "requires": { + "semver": "^7.1.3" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/semver/-/semver-7.3.5.tgz", + "integrity": "sha1-C2Ich5NI2JmOSw5L6Us/EuYBjvc=", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=" + } + } + }, + "@opentelemetry/exporter-collector": { + "version": "0.19.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@opentelemetry/exporter-collector/-/exporter-collector-0.19.0.tgz", + "integrity": "sha1-OI9whBh57WwNXv9jT7HWeY/pZ2g=", + "requires": { + "@opentelemetry/api-metrics": "0.19.0", + "@opentelemetry/core": "0.19.0", + "@opentelemetry/metrics": "0.19.0", + "@opentelemetry/resources": "0.19.0", + "@opentelemetry/tracing": "0.19.0" + } + }, + "@opentelemetry/exporter-collector-grpc": { + "version": "0.19.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@opentelemetry/exporter-collector-grpc/-/exporter-collector-grpc-0.19.0.tgz", + "integrity": "sha1-LLoxW3u0OZlT6+HRx2xXTIbvmf8=", + "requires": { + "@grpc/grpc-js": "^1.2.12", + "@grpc/proto-loader": "^0.6.0", + "@opentelemetry/core": "0.19.0", + "@opentelemetry/exporter-collector": "0.19.0", + "@opentelemetry/metrics": "0.19.0", + "@opentelemetry/resources": "0.19.0", + "@opentelemetry/tracing": "0.19.0" + } + }, + "@opentelemetry/instrumentation": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.19.0.tgz", + "integrity": "sha512-rvbJZNzgqVDO7/lvKdXoS6WJviJyV+d0lb43tF4cgFyXBvqNGCg8imS/Si4tBF0md1OvOjU+qNvjBKr/whXWOg==", + "requires": { + "@opentelemetry/api-metrics": "0.19.0", + "require-in-the-middle": "^5.0.3", + "semver": "^7.3.2", + "shimmer": "^1.2.1" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "@opentelemetry/instrumentation-express": { + "version": "0.16.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@opentelemetry/instrumentation-express/-/instrumentation-express-0.16.0.tgz", + "integrity": "sha1-Tv3DEvM2Mqn0JMGgrdzoEuMcKSM=", + "requires": { + "@opentelemetry/api": "^1.0.0-rc.0", + "@opentelemetry/core": "^0.19.0", + "@opentelemetry/instrumentation": "^0.19.0", + "@opentelemetry/semantic-conventions": "^0.19.0" + }, + "dependencies": { + "@opentelemetry/api": { + "version": "1.0.0-rc.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.0.0-rc.0.tgz", + "integrity": "sha512-iXKByCMfrlO5S6Oh97BuM56tM2cIBB0XsL/vWF/AtJrJEKx4MC/Xdu0xDsGXMGcNWpqF7ujMsjjnp0+UHBwnDQ==" + } + } + }, + "@opentelemetry/instrumentation-http": { + "version": "0.19.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@opentelemetry/instrumentation-http/-/instrumentation-http-0.19.0.tgz", + "integrity": "sha1-tUNyCcdCGqWfLwY1Irfv6c8zbPY=", + "requires": { + "@opentelemetry/instrumentation": "0.19.0", + "@opentelemetry/semantic-conventions": "0.19.0", + "semver": "^7.1.3" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/semver/-/semver-7.3.5.tgz", + "integrity": "sha1-C2Ich5NI2JmOSw5L6Us/EuYBjvc=", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=" + } + } + }, + "@opentelemetry/instrumentation-ioredis": { + "version": "0.16.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.16.0.tgz", + "integrity": "sha1-7yx7Mr2irzDCNXp6AqK4iWiPgzc=", + "requires": { + "@opentelemetry/api": "^1.0.0-rc.0", + "@opentelemetry/instrumentation": "^0.19.0", + "@opentelemetry/semantic-conventions": "^0.19.0" + }, + "dependencies": { + "@opentelemetry/api": { + "version": "1.0.0-rc.3", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@opentelemetry/api/-/api-1.0.0-rc.3.tgz", + "integrity": "sha1-kD723d8EQQ0JBy1DoGC4fMwWJUU=" + } + } + }, + "@opentelemetry/metrics": { + "version": "0.19.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@opentelemetry/metrics/-/metrics-0.19.0.tgz", + "integrity": "sha1-jsQJICo3Ogm1BSYdd0nzuynhRH0=", + "requires": { + "@opentelemetry/api-metrics": "0.19.0", + "@opentelemetry/core": "0.19.0", + "@opentelemetry/resources": "0.19.0", + "lodash.merge": "^4.6.2" + } + }, + "@opentelemetry/node": { + "version": "0.19.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@opentelemetry/node/-/node-0.19.0.tgz", + "integrity": "sha1-UYGw6smtPUcFKIMqlRaRSidCbpU=", + "requires": { + "@opentelemetry/context-async-hooks": "0.19.0", + "@opentelemetry/core": "0.19.0", + "@opentelemetry/propagator-b3": "0.19.0", + "@opentelemetry/propagator-jaeger": "0.19.0", + "@opentelemetry/tracing": "0.19.0", + "semver": "^7.1.3" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/semver/-/semver-7.3.5.tgz", + "integrity": "sha1-C2Ich5NI2JmOSw5L6Us/EuYBjvc=", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=" + } + } + }, + "@opentelemetry/propagator-b3": { + "version": "0.19.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@opentelemetry/propagator-b3/-/propagator-b3-0.19.0.tgz", + "integrity": "sha1-Dmh2sHBbTDVu1BSY/jKME+94r9s=" + }, + "@opentelemetry/propagator-jaeger": { + "version": "0.19.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@opentelemetry/propagator-jaeger/-/propagator-jaeger-0.19.0.tgz", + "integrity": "sha1-Z+XOCYaUcMpsse0nmmZc4ghK61E=", + "requires": { + "@opentelemetry/core": "0.19.0" + } + }, + "@opentelemetry/resources": { + "version": "0.19.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@opentelemetry/resources/-/resources-0.19.0.tgz", + "integrity": "sha1-OBNhD4lWoBo1P9lhrDk8AJlebT8=", + "requires": { + "@opentelemetry/core": "0.19.0" + } + }, + "@opentelemetry/semantic-conventions": { + "version": "0.19.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@opentelemetry/semantic-conventions/-/semantic-conventions-0.19.0.tgz", + "integrity": "sha1-Pkm0W1JCbGJ0CiT89YGMtpC0Ru8=" + }, + "@opentelemetry/tracing": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/tracing/-/tracing-0.19.0.tgz", + "integrity": "sha512-RUmPZLQi4+nlHwTFpHqU45TMW+osIraDtf0jcFKLacKltGIft65tVxIEVn1uF9N9eG7NZzjXLo3jsvCzpavJ8Q==", + "requires": { + "@opentelemetry/core": "0.19.0", + "@opentelemetry/resources": "0.19.0", + "@opentelemetry/semantic-conventions": "0.19.0", + "lodash.merge": "^4.6.2" + } + }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha1-TIVzDlm5ofHzSQR9vyQpYDS7JzU=" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha1-fvN/DQEPsCitGtWXIuUG2SYoFcs=" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", "requires": { - "once": "1.4.0", - "stack-trace": "0.0.9" + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" } }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@types/long/-/long-4.0.1.tgz", + "integrity": "sha1-RZxl+hhn2v5qjzIsTFFpVmPMVek=" + }, + "@types/node": { + "version": "15.0.2", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/@types/node/-/node-15.0.2.tgz", + "integrity": "sha1-UenAkg0bRZNuoENBqj4uWNM5+2c=" + }, "abbrev": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", @@ -24,7 +425,7 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", "requires": { - "mime-types": "2.1.12", + "mime-types": "~2.1.11", "negotiator": "0.6.1" } }, @@ -40,7 +441,7 @@ "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, "requires": { - "acorn": "3.3.0" + "acorn": "^3.0.4" }, "dependencies": { "acorn": { @@ -51,13 +452,36 @@ } } }, + "agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "requires": { + "debug": "^4.3.4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "ajv": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" } }, "ajv-keywords": { @@ -71,10 +495,11 @@ "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, + "optional": true, "requires": { - "kind-of": "3.2.2", - "longest": "1.0.1", - "repeat-string": "1.6.1" + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" } }, "amdefine": { @@ -89,7 +514,7 @@ "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", "dev": true, "requires": { - "string-width": "2.1.1" + "string-width": "^2.0.0" }, "dependencies": { "ansi-regex": { @@ -110,8 +535,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "strip-ansi": { @@ -120,11 +545,16 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } } } }, + "ansi-color": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-color/-/ansi-color-0.2.1.tgz", + "integrity": "sha1-PnXAN0dSF1RO12Oo21cJ+prlv5o=" + }, "ansi-escapes": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", @@ -149,8 +579,8 @@ "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", "dev": true, "requires": { - "micromatch": "2.3.11", - "normalize-path": "2.1.1" + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" } }, "argparse": { @@ -159,7 +589,7 @@ "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", "dev": true, "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" } }, "arr-diff": { @@ -168,7 +598,7 @@ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, "requires": { - "arr-flatten": "1.1.0" + "arr-flatten": "^1.0.1" } }, "arr-flatten": { @@ -206,7 +636,7 @@ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "1.0.3" + "array-uniq": "^1.0.1" } }, "array-uniq": { @@ -227,8 +657,8 @@ "integrity": "sha1-VWpcU2LAhkgyPdrrnenRS8GGTJA=", "dev": true, "requires": { - "define-properties": "1.1.2", - "es-abstract": "1.9.0" + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" } }, "arrify": { @@ -258,7 +688,7 @@ "resolved": "https://registry.npmjs.org/async/-/async-2.1.2.tgz", "integrity": "sha1-YSpKtF70KnDN6Aa62G7m2wR+g4U=", "requires": { - "lodash": "4.16.4" + "lodash": "^4.14.0" } }, "async-each": { @@ -288,9 +718,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" } }, "balanced-match": { @@ -299,6 +729,11 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, "basic-auth": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.4.tgz", @@ -310,15 +745,35 @@ "integrity": "sha1-PKdrhSQccXC/fZcD57mqdGMAQNQ=", "optional": true, "requires": { - "tweetnacl": "0.14.3" + "tweetnacl": "^0.14.3" } }, + "bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==" + }, "binary-extensions": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", "dev": true }, + "bindings": { + "version": "1.5.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha1-EDU8npRTNLwFEabZCzj7x8nFBN8=", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bintrees": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", + "integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=" + }, "bluebird": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", @@ -330,15 +785,15 @@ "integrity": "sha1-11eM9PHRHV9uqATO813Hp/9trmc=", "requires": { "bytes": "2.4.0", - "content-type": "1.0.2", - "debug": "2.2.0", - "depd": "1.1.0", - "http-errors": "1.5.0", + "content-type": "~1.0.2", + "debug": "~2.2.0", + "depd": "~1.1.0", + "http-errors": "~1.5.0", "iconv-lite": "0.4.13", - "on-finished": "2.3.0", + "on-finished": "~2.3.0", "qs": "6.2.0", - "raw-body": "2.1.7", - "type-is": "1.6.13" + "raw-body": "~2.1.7", + "type-is": "~1.6.13" } }, "boom": { @@ -346,7 +801,7 @@ "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "requires": { - "hoek": "2.16.3" + "hoek": "2.x.x" } }, "boxen": { @@ -355,13 +810,13 @@ "integrity": "sha1-Px1AMsMP/qnUsCwyLq8up0HcvOU=", "dev": true, "requires": { - "ansi-align": "2.0.0", - "camelcase": "4.1.0", - "chalk": "2.3.0", - "cli-boxes": "1.0.0", - "string-width": "2.1.1", - "term-size": "1.2.0", - "widest-line": "1.0.0" + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^1.0.0" }, "dependencies": { "ansi-regex": { @@ -376,7 +831,7 @@ "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", "dev": true, "requires": { - "color-convert": "1.9.1" + "color-convert": "^1.9.0" } }, "camelcase": { @@ -391,9 +846,9 @@ "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" + "ansi-styles": "^3.1.0", + "escape-string-regexp": "^1.0.5", + "supports-color": "^4.0.0" } }, "has-flag": { @@ -414,8 +869,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "strip-ansi": { @@ -424,7 +879,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } }, "supports-color": { @@ -433,7 +888,7 @@ "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { - "has-flag": "2.0.0" + "has-flag": "^2.0.0" } } } @@ -444,7 +899,7 @@ "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -454,9 +909,9 @@ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.2" + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" } }, "browser-stdout": { @@ -465,6 +920,22 @@ "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", "dev": true }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "bufrw": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bufrw/-/bufrw-1.3.0.tgz", + "integrity": "sha512-jzQnSbdJqhIltU9O5KUiTtljP9ccw2u5ix59McQy4pV2xGhVLhRZIndY8GIrgh5HjXa6+QJ9AQhOd2QWQizJFQ==", + "requires": { + "ansi-color": "^0.2.1", + "error": "^7.0.0", + "hexer": "^1.5.0", + "xtend": "^4.0.0" + } + }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", @@ -482,7 +953,7 @@ "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "dev": true, "requires": { - "callsites": "0.2.0" + "callsites": "^0.2.0" } }, "callsites": { @@ -517,8 +988,8 @@ "dev": true, "optional": true, "requires": { - "align-text": "0.1.4", - "lazy-cache": "1.0.4" + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" } }, "chai": { @@ -527,9 +998,9 @@ "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", "dev": true, "requires": { - "assertion-error": "1.0.2", - "deep-eql": "0.1.3", - "type-detect": "1.0.0" + "assertion-error": "^1.0.1", + "deep-eql": "^0.1.3", + "type-detect": "^1.0.0" } }, "chai-string": { @@ -544,11 +1015,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "chokidar": { @@ -557,15 +1028,15 @@ "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", "dev": true, "requires": { - "anymatch": "1.3.2", - "async-each": "1.0.1", - "fsevents": "1.1.3", - "glob-parent": "2.0.0", - "inherits": "2.0.1", - "is-binary-path": "1.0.1", - "is-glob": "2.0.1", - "path-is-absolute": "1.0.1", - "readdirp": "2.1.0" + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" } }, "circular-json": { @@ -586,7 +1057,7 @@ "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", "dev": true, "requires": { - "restore-cursor": "1.0.1" + "restore-cursor": "^1.0.1" } }, "cli-width": { @@ -602,8 +1073,8 @@ "dev": true, "optional": true, "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", + "center-align": "^0.1.1", + "right-align": "^0.1.1", "wordwrap": "0.0.2" }, "dependencies": { @@ -638,7 +1109,7 @@ "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", "dev": true, "requires": { - "color-name": "1.1.3" + "color-name": "^1.1.1" } }, "color-name": { @@ -657,7 +1128,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "commander": { @@ -666,7 +1137,7 @@ "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", "dev": true, "requires": { - "graceful-readlink": "1.0.1" + "graceful-readlink": ">= 1.0.0" } }, "component-emitter": { @@ -687,9 +1158,9 @@ "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", "dev": true, "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3", - "typedarray": "0.0.6" + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" }, "dependencies": { "inherits": { @@ -706,12 +1177,12 @@ "integrity": "sha512-5oNkD/L++l0O6xGXxb1EWS7SivtjfGQlRyxJsYgE0Z495/L81e2h4/d3r969hoPXuFItzNOKMtsXgYG4c7dYvw==", "dev": true, "requires": { - "dot-prop": "4.2.0", - "graceful-fs": "4.1.11", - "make-dir": "1.1.0", - "unique-string": "1.0.0", - "write-file-atomic": "2.3.0", - "xdg-basedir": "3.0.0" + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" } }, "contains-path": { @@ -777,8 +1248,8 @@ "integrity": "sha1-bl/mfYsgXOTSL60Ft3geja3MSzA=", "dev": true, "requires": { - "argparse": "1.0.9", - "esprima": "2.7.3" + "argparse": "^1.0.7", + "esprima": "^2.6.0" } }, "minimist": { @@ -799,26 +1270,26 @@ "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", "dev": true, "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.5.0", - "caseless": "0.11.0", - "combined-stream": "1.0.5", - "extend": "3.0.0", - "forever-agent": "0.6.1", - "form-data": "2.1.1", - "har-validator": "2.0.6", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.12", - "oauth-sign": "0.8.2", - "qs": "6.3.2", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.4.3", - "uuid": "3.0.1" + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "caseless": "~0.11.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.1.1", + "har-validator": "~2.0.6", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "oauth-sign": "~0.8.1", + "qs": "~6.3.0", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "~0.4.1", + "uuid": "^3.0.0" } } } @@ -829,7 +1300,7 @@ "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", "dev": true, "requires": { - "capture-stack-trace": "1.0.0" + "capture-stack-trace": "^1.0.0" } }, "cross-spawn": { @@ -838,9 +1309,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.1", - "shebang-command": "1.2.0", - "which": "1.3.0" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "cryptiles": { @@ -848,7 +1319,7 @@ "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", "requires": { - "boom": "2.10.1" + "boom": "2.x.x" } }, "crypto-random-string": { @@ -868,7 +1339,7 @@ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { - "es5-ext": "0.10.35" + "es5-ext": "^0.10.9" } }, "damerau-levenshtein": { @@ -882,7 +1353,7 @@ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.0.tgz", "integrity": "sha1-KeSGxUGL8PNWA0qZPVFoajPoQUE=", "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" }, "dependencies": { "assert-plus": { @@ -947,8 +1418,8 @@ "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", "dev": true, "requires": { - "foreach": "2.0.5", - "object-keys": "1.0.11" + "foreach": "^2.0.5", + "object-keys": "^1.0.8" } }, "del": { @@ -957,13 +1428,13 @@ "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "dev": true, "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.0", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" } }, "delayed-stream": { @@ -998,8 +1469,8 @@ "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", "dev": true, "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" + "esutils": "^2.0.2", + "isarray": "^1.0.0" } }, "dot-prop": { @@ -1008,7 +1479,7 @@ "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", "dev": true, "requires": { - "is-obj": "1.0.1" + "is-obj": "^1.0.0" } }, "duplexer": { @@ -1029,7 +1500,15 @@ "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", "optional": true, "requires": { - "jsbn": "0.1.0" + "jsbn": "~0.1.0" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" } }, "ee-first": { @@ -1037,22 +1516,36 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=" + }, "encodeurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=" }, + "error": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", + "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", + "requires": { + "string-template": "~0.2.1", + "xtend": "~4.0.0" + } + }, "es-abstract": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.9.0.tgz", "integrity": "sha512-kk3IJoKo7A3pWJc0OV8yZ/VEX2oSUytfekrJiqoxBlKJMFAJVJVpGdHClCCTdv+Fn2zHfpDHHIelMFhZVfef3Q==", "dev": true, "requires": { - "es-to-primitive": "1.1.1", - "function-bind": "1.1.1", - "has": "1.0.1", - "is-callable": "1.1.3", - "is-regex": "1.0.4" + "es-to-primitive": "^1.1.1", + "function-bind": "^1.1.1", + "has": "^1.0.1", + "is-callable": "^1.1.3", + "is-regex": "^1.0.4" } }, "es-to-primitive": { @@ -1061,9 +1554,9 @@ "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", "dev": true, "requires": { - "is-callable": "1.1.3", - "is-date-object": "1.0.1", - "is-symbol": "1.0.1" + "is-callable": "^1.1.1", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.1" } }, "es5-ext": { @@ -1072,8 +1565,8 @@ "integrity": "sha1-GO6FjOajxFx9eekcFfzKnsVoSU8=", "dev": true, "requires": { - "es6-iterator": "2.0.3", - "es6-symbol": "3.1.1" + "es6-iterator": "~2.0.1", + "es6-symbol": "~3.1.1" } }, "es6-iterator": { @@ -1082,9 +1575,9 @@ "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.35", - "es6-symbol": "3.1.1" + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" } }, "es6-map": { @@ -1093,12 +1586,12 @@ "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.35", - "es6-iterator": "2.0.3", - "es6-set": "0.1.5", - "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" } }, "es6-promise": { @@ -1113,11 +1606,11 @@ "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.35", - "es6-iterator": "2.0.3", + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" + "event-emitter": "~0.3.5" } }, "es6-symbol": { @@ -1126,8 +1619,8 @@ "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.35" + "d": "1", + "es5-ext": "~0.10.14" } }, "es6-weak-map": { @@ -1136,12 +1629,17 @@ "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.35", - "es6-iterator": "2.0.3", - "es6-symbol": "3.1.1" + "d": "1", + "es5-ext": "^0.10.14", + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" } }, + "escalade": { + "version": "3.1.1", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha1-2M/ccACWXFoBdLSoLqpcBVJ0LkA=" + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1159,11 +1657,11 @@ "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", "dev": true, "requires": { - "esprima": "2.7.3", - "estraverse": "1.9.3", - "esutils": "2.0.2", - "optionator": "0.8.2", - "source-map": "0.2.0" + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" }, "dependencies": { "esprima": { @@ -1186,10 +1684,10 @@ "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", "dev": true, "requires": { - "es6-map": "0.1.5", - "es6-weak-map": "2.0.2", - "esrecurse": "4.2.0", - "estraverse": "4.2.0" + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, "eslint": { @@ -1198,41 +1696,41 @@ "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "chalk": "1.1.3", - "concat-stream": "1.6.0", - "debug": "2.2.0", - "doctrine": "2.0.0", - "escope": "3.6.0", - "espree": "3.5.2", - "esquery": "1.0.0", - "estraverse": "4.2.0", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "glob": "7.1.2", - "globals": "9.18.0", - "ignore": "3.3.7", - "imurmurhash": "0.1.4", - "inquirer": "0.12.0", - "is-my-json-valid": "2.16.1", - "is-resolvable": "1.0.0", - "js-yaml": "3.10.0", - "json-stable-stringify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.16.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "1.2.1", - "progress": "1.1.8", - "require-uncached": "1.0.3", - "shelljs": "0.7.8", - "strip-bom": "3.0.0", - "strip-json-comments": "2.0.1", - "table": "3.8.3", - "text-table": "0.2.0", - "user-home": "2.0.0" + "babel-code-frame": "^6.16.0", + "chalk": "^1.1.3", + "concat-stream": "^1.5.2", + "debug": "^2.1.1", + "doctrine": "^2.0.0", + "escope": "^3.6.0", + "espree": "^3.4.0", + "esquery": "^1.0.0", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "glob": "^7.0.3", + "globals": "^9.14.0", + "ignore": "^3.2.0", + "imurmurhash": "^0.1.4", + "inquirer": "^0.12.0", + "is-my-json-valid": "^2.10.0", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.5.1", + "json-stable-stringify": "^1.0.0", + "levn": "^0.3.0", + "lodash": "^4.0.0", + "mkdirp": "^0.5.0", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.1", + "pluralize": "^1.2.1", + "progress": "^1.1.8", + "require-uncached": "^1.0.2", + "shelljs": "^0.7.5", + "strip-bom": "^3.0.0", + "strip-json-comments": "~2.0.1", + "table": "^3.7.8", + "text-table": "~0.2.0", + "user-home": "^2.0.0" } }, "eslint-config-airbnb": { @@ -1241,7 +1739,7 @@ "integrity": "sha1-qygrdWol8D0ErCZMJNZzoIqAMnA=", "dev": true, "requires": { - "eslint-config-airbnb-base": "8.0.0" + "eslint-config-airbnb-base": "^8.0.0" } }, "eslint-config-airbnb-base": { @@ -1256,9 +1754,9 @@ "integrity": "sha1-Wt2BBujJKNssuiMrzZ76hG49oWw=", "dev": true, "requires": { - "debug": "2.2.0", - "object-assign": "4.1.1", - "resolve": "1.5.0" + "debug": "^2.2.0", + "object-assign": "^4.0.1", + "resolve": "^1.1.6" } }, "eslint-plugin-import": { @@ -1267,22 +1765,22 @@ "integrity": "sha1-svoH68xTUE0PKkR3WC7Iv/GHG58=", "dev": true, "requires": { - "builtin-modules": "1.1.1", - "contains-path": "0.1.0", - "debug": "2.2.0", - "doctrine": "1.3.0", - "es6-map": "0.1.5", - "es6-set": "0.1.5", - "eslint-import-resolver-node": "0.2.3", - "has": "1.0.1", - "lodash.cond": "4.5.2", - "lodash.endswith": "4.2.1", - "lodash.find": "4.6.0", - "lodash.findindex": "4.6.0", - "minimatch": "3.0.4", - "object-assign": "4.1.1", - "pkg-dir": "1.0.0", - "pkg-up": "1.0.0" + "builtin-modules": "^1.1.1", + "contains-path": "^0.1.0", + "debug": "^2.2.0", + "doctrine": "1.3.x", + "es6-map": "^0.1.3", + "es6-set": "^0.1.4", + "eslint-import-resolver-node": "^0.2.0", + "has": "^1.0.1", + "lodash.cond": "^4.3.0", + "lodash.endswith": "^4.0.1", + "lodash.find": "^4.3.0", + "lodash.findindex": "^4.3.0", + "minimatch": "^3.0.3", + "object-assign": "^4.0.1", + "pkg-dir": "^1.0.0", + "pkg-up": "^1.0.0" }, "dependencies": { "doctrine": { @@ -1291,8 +1789,8 @@ "integrity": "sha1-E+dWgrVVGEJCdvfBc3g0Vu+RPSY=", "dev": true, "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" + "esutils": "^2.0.2", + "isarray": "^1.0.0" } } } @@ -1303,9 +1801,9 @@ "integrity": "sha1-TjXLcbin23AqxBXIBuuOjZ6mxl0=", "dev": true, "requires": { - "damerau-levenshtein": "1.0.4", - "jsx-ast-utils": "1.4.1", - "object-assign": "4.1.1" + "damerau-levenshtein": "^1.0.0", + "jsx-ast-utils": "^1.0.0", + "object-assign": "^4.0.1" } }, "eslint-plugin-react": { @@ -1314,11 +1812,11 @@ "integrity": "sha1-xUNb6wZ3ThLH2y9qut3L+QDNP3g=", "dev": true, "requires": { - "array.prototype.find": "2.0.4", - "doctrine": "1.5.0", - "has": "1.0.1", - "jsx-ast-utils": "1.4.1", - "object.assign": "4.0.4" + "array.prototype.find": "^2.0.1", + "doctrine": "^1.2.2", + "has": "^1.0.1", + "jsx-ast-utils": "^1.3.4", + "object.assign": "^4.0.4" }, "dependencies": { "doctrine": { @@ -1327,8 +1825,8 @@ "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", "dev": true, "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" + "esutils": "^2.0.2", + "isarray": "^1.0.0" } } } @@ -1339,8 +1837,8 @@ "integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==", "dev": true, "requires": { - "acorn": "5.2.1", - "acorn-jsx": "3.0.1" + "acorn": "^5.2.1", + "acorn-jsx": "^3.0.0" } }, "esprima": { @@ -1355,7 +1853,7 @@ "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", "dev": true, "requires": { - "estraverse": "4.2.0" + "estraverse": "^4.0.0" } }, "esrecurse": { @@ -1364,8 +1862,8 @@ "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", "dev": true, "requires": { - "estraverse": "4.2.0", - "object-assign": "4.1.1" + "estraverse": "^4.1.0", + "object-assign": "^4.0.1" } }, "estraverse": { @@ -1391,8 +1889,8 @@ "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.35" + "d": "1", + "es5-ext": "~0.10.14" } }, "event-stream": { @@ -1401,13 +1899,13 @@ "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { - "duplexer": "0.1.1", - "from": "0.1.7", - "map-stream": "0.1.0", + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", "pause-stream": "0.0.11", - "split": "0.3.3", - "stream-combiner": "0.0.4", - "through": "2.3.8" + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" } }, "eventemitter3": { @@ -1422,13 +1920,13 @@ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, "exit-hook": { @@ -1443,7 +1941,7 @@ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, "requires": { - "is-posix-bracket": "0.1.1" + "is-posix-bracket": "^0.1.0" } }, "expand-range": { @@ -1452,7 +1950,7 @@ "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", "dev": true, "requires": { - "fill-range": "2.2.3" + "fill-range": "^2.1.0" } }, "express": { @@ -1460,32 +1958,40 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.14.0.tgz", "integrity": "sha1-we4/Qs3Ikfs9xlCoki1R7IR9DWY=", "requires": { - "accepts": "1.3.3", + "accepts": "~1.3.3", "array-flatten": "1.1.1", "content-disposition": "0.5.1", - "content-type": "1.0.2", + "content-type": "~1.0.2", "cookie": "0.3.1", "cookie-signature": "1.0.6", - "debug": "2.2.0", - "depd": "1.1.0", - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "etag": "1.7.0", + "debug": "~2.2.0", + "depd": "~1.1.0", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "etag": "~1.7.0", "finalhandler": "0.5.0", "fresh": "0.3.0", "merge-descriptors": "1.0.1", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.1", "path-to-regexp": "0.1.7", - "proxy-addr": "1.1.2", + "proxy-addr": "~1.1.2", "qs": "6.2.0", - "range-parser": "1.2.0", + "range-parser": "~1.2.0", "send": "0.14.1", - "serve-static": "1.11.1", - "type-is": "1.6.13", + "serve-static": "~1.11.1", + "type-is": "~1.6.13", "utils-merge": "1.0.0", - "vary": "1.1.0" + "vary": "~1.1.0" + } + }, + "express-opentracing": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/express-opentracing/-/express-opentracing-0.1.1.tgz", + "integrity": "sha512-urVTRTn/Y9/oSjy/P+IOWOl2Db0MnLqS7qYicHWk7vbL6ld+TNRp0DRx5G7cK2mLQ+/Ovpt8c4WLyG97VmtEdA==", + "requires": { + "opentracing": "^0.14.0" } }, "extend": { @@ -1499,7 +2005,7 @@ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "extsprintf": { @@ -1524,8 +2030,8 @@ "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", "dev": true, "requires": { - "escape-string-regexp": "1.0.5", - "object-assign": "4.1.1" + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" } }, "file-entry-cache": { @@ -1534,10 +2040,17 @@ "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", "dev": true, "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" } }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha1-VTp7hEb/b2hDWcRF8eN6BdrMM90=", + "dev": true, + "optional": true + }, "filename-regex": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", @@ -1550,11 +2063,11 @@ "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", "dev": true, "requires": { - "is-number": "2.1.0", - "isobject": "2.1.0", - "randomatic": "1.1.7", - "repeat-element": "1.1.2", - "repeat-string": "1.6.1" + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^1.1.3", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" } }, "finalhandler": { @@ -1562,11 +2075,11 @@ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.5.0.tgz", "integrity": "sha1-6VCKvs6bbbqHGmlCodeRG5GRGsc=", "requires": { - "debug": "2.2.0", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "statuses": "1.3.0", - "unpipe": "1.0.0" + "debug": "~2.2.0", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "statuses": "~1.3.0", + "unpipe": "~1.0.0" } }, "find-up": { @@ -1575,8 +2088,8 @@ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "flat-cache": { @@ -1585,10 +2098,10 @@ "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", "dev": true, "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" + "circular-json": "^0.3.1", + "del": "^2.0.2", + "graceful-fs": "^4.1.2", + "write": "^0.2.1" } }, "flexbuffer": { @@ -1608,7 +2121,7 @@ "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", "dev": true, "requires": { - "for-in": "1.0.2" + "for-in": "^1.0.1" } }, "foreach": { @@ -1623,10 +2136,10 @@ "integrity": "sha1-AKzSD5274vedBGl7zKKnfuAO4DE=", "dev": true, "requires": { - "commander": "2.9.0", - "http-proxy": "1.11.3", - "mustache": "2.3.0", - "shell-quote": "1.4.3" + "commander": "~2.9.0", + "http-proxy": "~1.11.1", + "mustache": "^2.2.1", + "shell-quote": "~1.4.2" } }, "forever-agent": { @@ -1639,18 +2152,18 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.1.tgz", "integrity": "sha1-St8DQuGnmvoehMjDIKn/yCOSofM=", "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.12" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" } }, "formatio": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz", - "integrity": "sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz", + "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=", "dev": true, "requires": { - "samsam": "1.1.2" + "samsam": "1.x" } }, "formidable": { @@ -1682,1045 +2195,81 @@ "dev": true }, "fsevents": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", - "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", + "version": "1.2.13", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha1-8yXLBFVZJCi88Rs4M3DvcOO/zDg=", "dev": true, "optional": true, "requires": { - "nan": "2.8.0", - "node-pre-gyp": "0.6.39" - }, - "dependencies": { - "abbrev": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", - "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=", - "dev": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dev": true, - "optional": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "aproba": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.1.1.tgz", - "integrity": "sha1-ldNgDwdxCqDpKYxyatXs8urLq6s=", - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", - "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", - "dev": true, - "optional": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.2.9" - } - }, - "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", - "dev": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "dev": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", - "dev": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "block-stream": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", - "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", - "dev": true, - "requires": { - "inherits": "2.0.3" - } - }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "brace-expansion": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", - "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=", - "dev": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", - "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "combined-stream": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", - "dev": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dev": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", - "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=", - "dev": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.2.tgz", - "integrity": "sha1-ca1dIEvxempsqPRQxhRUBm70YeE=", - "dev": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", - "dev": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", - "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true, - "optional": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fstream": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", - "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.1" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz", - "integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=", - "dev": true, - "optional": true, - "requires": { - "fstream": "1.0.11", - "inherits": "2.0.3", - "minimatch": "3.0.4" - } - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "optional": true, - "requires": { - "aproba": "1.1.1", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true - }, - "har-schema": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", - "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", - "dev": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", - "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", - "dev": true, - "optional": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true - }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.0" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "ini": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", - "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz", - "integrity": "sha1-BtSRIlUJNBlHfUJWM2BuDpB4KWc=", - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", - "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", - "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=", - "dev": true - }, - "mime-types": { - "version": "2.1.15", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", - "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", - "dev": true, - "requires": { - "mime-db": "1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.39", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz", - "integrity": "sha512-OsJV74qxnvz/AMGgcfZoDaeDXKD3oY3QVIbBmwszTFkRisTSXbMQyn4UWzUMOtA5SVhrBZOTp0wcoSBgfMfMmQ==", - "dev": true, - "optional": true, - "requires": { - "detect-libc": "1.0.2", - "hawk": "3.1.3", - "mkdirp": "0.5.1", - "nopt": "4.0.1", - "npmlog": "4.1.0", - "rc": "1.2.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "semver": "5.3.0", - "tar": "2.2.1", - "tar-pack": "3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", - "dev": true, - "optional": true, - "requires": { - "abbrev": "1.1.0", - "osenv": "0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.0.tgz", - "integrity": "sha512-ocolIkZYZt8UveuiDS0yAkkIjid1o7lPG8cYm05yNYzBn8ykQtaiPMEGp8fY9tKdDgm8okpdKzkvu1y9hUYugA==", - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", - "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", - "dev": true, - "optional": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "performance-now": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", - "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz", - "integrity": "sha1-LgPo5C7kULjLPc5lvhv4l04d/ZU=", - "dev": true, - "optional": true, - "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.4", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", - "integrity": "sha1-z3jsb0ptHrQ9JkiMrJfwQudLf8g=", - "dev": true, - "requires": { - "buffer-shims": "1.0.0", - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "1.0.1", - "util-deprecate": "1.0.2" - } - }, - "request": { - "version": "2.81.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", - "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.0.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.0.1" - } - }, - "rimraf": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", - "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", - "dev": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz", - "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=", - "dev": true - }, - "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "sshpk": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.0.tgz", - "integrity": "sha1-/yo+T9BEl1Vf7Zezmg/YL6+zozw=", - "dev": true, - "optional": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jodid25519": "1.0.2", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "optional": true - } - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "string_decoder": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.1.tgz", - "integrity": "sha1-YuIA8DmVWmgQ2N8KM//A8BNmLZg=", - "dev": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", - "dev": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", - "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", - "dev": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - }, - "tar-pack": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.0.tgz", - "integrity": "sha1-I74tf2cagzk3bL2wuP4/3r8xeYQ=", - "dev": true, - "optional": true, - "requires": { - "debug": "2.6.8", - "fstream": "1.0.11", - "fstream-ignore": "1.0.5", - "once": "1.4.0", - "readable-stream": "2.2.9", - "rimraf": "2.6.1", - "tar": "2.2.1", - "uid-number": "0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", - "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", - "dev": true, - "optional": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", - "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=", - "dev": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "uuid": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz", - "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=", - "dev": true, - "optional": true + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "gaxios": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.1.1.tgz", + "integrity": "sha512-bw8smrX+XlAoo9o1JAksBwX+hi/RG15J+NTSxmNPIclKC3ZVK6C2afwY8OSdRvOK0+ZLecUJYtj2MmjOt3Dm0w==", + "requires": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9" + }, + "dependencies": { + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, - "verror": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", - "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", - "dev": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" - } + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" }, - "wide-align": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", - "dev": true, - "optional": true, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "requires": { - "string-width": "1.0.2" + "whatwg-url": "^5.0.0" } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true } } }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "gcp-metadata": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", + "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "requires": { + "gaxios": "^6.0.0", + "json-bigint": "^1.0.0" + } }, - "gelf-pro": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/gelf-pro/-/gelf-pro-1.1.0.tgz", - "integrity": "sha1-0Twh8cOr2QO0F6xCh+a6CxL2+zY=", + "gelf": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/gelf/-/gelf-2.0.1.tgz", + "integrity": "sha512-77duTNPkUgcwFRl+kbmPx2YGMF4e030xBVVsKix5mruTAjuROW36WxmpVSk8MkiZC1D68JYNNb+kfJeZG/D5VQ==", "requires": { - "async": "2.0.1", - "lodash": "4.16.4" + "async": "^2.5.0" }, "dependencies": { "async": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.0.1.tgz", - "integrity": "sha1-twnMAoCpw28J9FNr6CPIOKkEniU=", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", "requires": { - "lodash": "4.16.4" + "lodash": "^4.17.11" } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" } } }, @@ -2736,9 +2285,14 @@ "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", "dev": true, "requires": { - "is-property": "1.0.2" + "is-property": "^1.0.0" } }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha1-T5RBKoLbMvNuOwuXQfipf+sDH34=" + }, "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", @@ -2750,7 +2304,7 @@ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz", "integrity": "sha1-KD/9n8ElaECHUxHBtg6MQBhxEOY=", "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" }, "dependencies": { "assert-plus": { @@ -2766,12 +2320,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.1", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "glob-base": { @@ -2780,8 +2334,8 @@ "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", "dev": true, "requires": { - "glob-parent": "2.0.0", - "is-glob": "2.0.1" + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" } }, "glob-parent": { @@ -2790,7 +2344,7 @@ "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", "dev": true, "requires": { - "is-glob": "2.0.1" + "is-glob": "^2.0.0" } }, "global-dirs": { @@ -2799,7 +2353,7 @@ "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", "dev": true, "requires": { - "ini": "1.3.5" + "ini": "^1.3.4" } }, "globals": { @@ -2814,12 +2368,25 @@ "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "dev": true, "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "google-auth-library": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.2.0.tgz", + "integrity": "sha512-1oV3p0JhNEhVbj26eF3FAJcv9MXXQt4S0wcvKZaDbl4oHq5V3UJoSbsGZGQNcjoCdhW4kDSwOs11wLlHog3fgQ==", + "requires": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.0.0", + "gcp-metadata": "^6.0.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" } }, "got": { @@ -2828,17 +2395,17 @@ "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", "dev": true, "requires": { - "create-error-class": "3.0.2", - "duplexer3": "0.1.4", - "get-stream": "3.0.0", - "is-redirect": "1.0.0", - "is-retry-allowed": "1.1.0", - "is-stream": "1.1.0", - "lowercase-keys": "1.0.0", - "safe-buffer": "5.1.1", - "timed-out": "4.0.1", - "unzip-response": "2.0.1", - "url-parse-lax": "1.0.0" + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" } }, "graceful-fs": { @@ -2859,16 +2426,25 @@ "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", "dev": true }, + "gtoken": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.0.1.tgz", + "integrity": "sha512-KcFVtoP1CVFtQu0aSk3AyAt2og66PFhZAlkUOuWKwzMLoulHXG5W5wE5xAnHb+yl3/wEFoqGW7/cDGMU8igDZQ==", + "requires": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + } + }, "handlebars": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", "dev": true, "requires": { - "async": "1.5.2", - "optimist": "0.6.1", - "source-map": "0.4.4", - "uglify-js": "2.8.29" + "async": "^1.4.0", + "optimist": "^0.6.1", + "source-map": "^0.4.4", + "uglify-js": "^2.6" }, "dependencies": { "async": { @@ -2883,7 +2459,7 @@ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } } } @@ -2899,10 +2475,10 @@ "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", "dev": true, "requires": { - "chalk": "1.1.3", - "commander": "2.9.0", - "is-my-json-valid": "2.16.1", - "pinkie-promise": "2.0.1" + "chalk": "^1.1.1", + "commander": "^2.9.0", + "is-my-json-valid": "^2.12.4", + "pinkie-promise": "^2.0.0" } }, "has": { @@ -2911,7 +2487,7 @@ "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", "dev": true, "requires": { - "function-bind": "1.1.1" + "function-bind": "^1.0.2" } }, "has-ansi": { @@ -2920,7 +2496,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "has-flag": { @@ -2934,10 +2510,10 @@ "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" } }, "he": { @@ -2946,6 +2522,24 @@ "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", "dev": true }, + "hexer": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/hexer/-/hexer-1.5.0.tgz", + "integrity": "sha1-uGzoCFmOip0YksVx887dhvyfBlM=", + "requires": { + "ansi-color": "^0.2.1", + "minimist": "^1.1.0", + "process": "^0.10.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + } + } + }, "hoek": { "version": "2.16.3", "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", @@ -2958,7 +2552,7 @@ "requires": { "inherits": "2.0.1", "setprototypeof": "1.0.1", - "statuses": "1.3.0" + "statuses": ">= 1.3.0 < 2" } }, "http-proxy": { @@ -2967,8 +2561,8 @@ "integrity": "sha1-GRXciIdR4qa/PCq/yxgI+obHI1M=", "dev": true, "requires": { - "eventemitter3": "1.2.0", - "requires-port": "0.0.1" + "eventemitter3": "1.x.x", + "requires-port": "0.x.x" } }, "http-signature": { @@ -2976,9 +2570,33 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.3.1", - "sshpk": "1.10.1" + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } } }, "iconv-lite": { @@ -3016,8 +2634,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -3037,19 +2655,19 @@ "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", "dev": true, "requires": { - "ansi-escapes": "1.4.0", - "ansi-regex": "2.1.1", - "chalk": "1.1.3", - "cli-cursor": "1.0.2", - "cli-width": "2.2.0", - "figures": "1.7.0", - "lodash": "4.16.4", - "readline2": "1.0.1", - "run-async": "0.1.0", - "rx-lite": "3.1.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "through": "2.3.8" + "ansi-escapes": "^1.1.0", + "ansi-regex": "^2.0.0", + "chalk": "^1.0.0", + "cli-cursor": "^1.0.1", + "cli-width": "^2.0.0", + "figures": "^1.3.5", + "lodash": "^4.3.0", + "readline2": "^1.0.1", + "run-async": "^0.1.0", + "rx-lite": "^3.1.2", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" } }, "interpret": { @@ -3063,29 +2681,29 @@ "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-3.1.4.tgz", "integrity": "sha512-gz9h5BVDh5DVfzGAzyUsE/NBABLuDN5inIFKKRq66h9mqtpBFSM5HaOxKgkJLwMhQihZPkadq/xaZP4dlrHwXA==", "requires": { - "bluebird": "3.5.1", - "cluster-key-slot": "1.0.8", - "debug": "2.2.0", - "denque": "1.2.2", + "bluebird": "^3.3.4", + "cluster-key-slot": "^1.0.6", + "debug": "^2.2.0", + "denque": "^1.1.0", "flexbuffer": "0.0.6", - "lodash.assign": "4.2.0", - "lodash.bind": "4.2.1", - "lodash.clone": "4.5.0", - "lodash.clonedeep": "4.5.0", - "lodash.defaults": "4.2.0", - "lodash.difference": "4.5.0", - "lodash.flatten": "4.4.0", - "lodash.foreach": "4.5.0", - "lodash.isempty": "4.4.0", - "lodash.keys": "4.2.0", - "lodash.noop": "3.0.1", - "lodash.partial": "4.2.1", - "lodash.pick": "4.4.0", - "lodash.sample": "4.2.1", - "lodash.shuffle": "4.2.0", - "lodash.values": "4.3.0", - "redis-commands": "1.3.1", - "redis-parser": "2.6.0" + "lodash.assign": "^4.2.0", + "lodash.bind": "^4.2.1", + "lodash.clone": "^4.5.0", + "lodash.clonedeep": "^4.5.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.foreach": "^4.5.0", + "lodash.isempty": "^4.4.0", + "lodash.keys": "^4.2.0", + "lodash.noop": "^3.0.1", + "lodash.partial": "^4.2.1", + "lodash.pick": "^4.4.0", + "lodash.sample": "^4.2.1", + "lodash.shuffle": "^4.2.0", + "lodash.values": "^4.3.0", + "redis-commands": "^1.2.0", + "redis-parser": "^2.4.0" }, "dependencies": { "lodash.assign": { @@ -3116,7 +2734,7 @@ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "dev": true, "requires": { - "binary-extensions": "1.11.0" + "binary-extensions": "^1.0.0" } }, "is-buffer": { @@ -3131,6 +2749,24 @@ "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", "dev": true }, + "is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "requires": { + "has": "^1.0.3" + }, + "dependencies": { + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + } + } + }, "is-date-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", @@ -3149,7 +2785,7 @@ "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", "dev": true, "requires": { - "is-primitive": "2.0.0" + "is-primitive": "^2.0.0" } }, "is-extendable": { @@ -3170,7 +2806,7 @@ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-glob": { @@ -3179,7 +2815,7 @@ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "is-installed-globally": { @@ -3188,8 +2824,8 @@ "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", "dev": true, "requires": { - "global-dirs": "0.1.1", - "is-path-inside": "1.0.0" + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" } }, "is-my-json-valid": { @@ -3198,10 +2834,10 @@ "integrity": "sha512-ochPsqWS1WXj8ZnMIV0vnNXooaMhp7cyL4FMSIPKTtnV0Ha/T19G2b9kkhcNsabV9bxYkze7/aLZJb/bYuFduQ==", "dev": true, "requires": { - "generate-function": "2.0.0", - "generate-object-property": "1.2.0", - "jsonpointer": "4.0.1", - "xtend": "4.0.1" + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "jsonpointer": "^4.0.0", + "xtend": "^4.0.0" } }, "is-npm": { @@ -3216,7 +2852,7 @@ "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } }, "is-obj": { @@ -3237,7 +2873,7 @@ "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", "dev": true, "requires": { - "is-path-inside": "1.0.0" + "is-path-inside": "^1.0.0" } }, "is-path-inside": { @@ -3246,7 +2882,7 @@ "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", "dev": true, "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.1" } }, "is-posix-bracket": { @@ -3279,7 +2915,7 @@ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "dev": true, "requires": { - "has": "1.0.1" + "has": "^1.0.1" } }, "is-resolvable": { @@ -3288,7 +2924,7 @@ "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", "dev": true, "requires": { - "tryit": "1.0.3" + "tryit": "^1.0.1" } }, "is-retry-allowed": { @@ -3346,20 +2982,20 @@ "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", "dev": true, "requires": { - "abbrev": "1.0.9", - "async": "1.5.2", - "escodegen": "1.8.1", - "esprima": "2.7.3", - "glob": "5.0.15", - "handlebars": "4.0.11", - "js-yaml": "3.10.0", - "mkdirp": "0.5.1", - "nopt": "3.0.6", - "once": "1.4.0", - "resolve": "1.1.7", - "supports-color": "3.2.3", - "which": "1.3.0", - "wordwrap": "1.0.0" + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" }, "dependencies": { "async": { @@ -3380,11 +3016,11 @@ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", "dev": true, "requires": { - "inflight": "1.0.6", - "inherits": "2.0.1", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "resolve": { @@ -3399,7 +3035,7 @@ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, "requires": { - "has-flag": "1.0.0" + "has-flag": "^1.0.0" } } } @@ -3410,11 +3046,11 @@ "integrity": "sha1-TxwVkr4QTVkfkzy/nA8vUoStzwA=", "dev": true, "requires": { - "chalk": "1.1.3", - "coveralls": "2.13.3", - "minimist": "1.2.0", - "rimraf": "2.6.2", - "sum-up": "1.0.3" + "chalk": "^1.0.0", + "coveralls": "^2.11.2", + "minimist": "^1.1.1", + "rimraf": "^2.3.4", + "sum-up": "^1.0.1" }, "dependencies": { "minimist": { @@ -3425,13 +3061,32 @@ } } }, + "jaeger-client": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/jaeger-client/-/jaeger-client-3.18.0.tgz", + "integrity": "sha512-xZ9WvZDWLkZFq7SObpLwu1asMCKCgBRNcDxxGSvK+ZQ7OZyJC5xPlU+rJa4+s/P6autPBVwHpqMGbOERFxWuuA==", + "requires": { + "node-int64": "^0.4.0", + "opentracing": "^0.14.4", + "thriftrw": "^3.5.0", + "uuid": "^3.2.1", + "xorshift": "^0.2.0" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, "jodid25519": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz", "integrity": "sha1-BtSRIlUJNBlHfUJWM2BuDpB4KWc=", "optional": true, "requires": { - "jsbn": "0.1.0" + "jsbn": "~0.1.0" } }, "js-tokens": { @@ -3446,8 +3101,8 @@ "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", "dev": true, "requires": { - "argparse": "1.0.9", - "esprima": "4.0.0" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, "jsbn": { @@ -3456,6 +3111,14 @@ "integrity": "sha1-ZQmH2g3XT06/WhE3eiqi0nPpff0=", "optional": true }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -3466,7 +3129,7 @@ "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "requires": { - "jsonify": "0.0.0" + "jsonify": "~0.0.0" } }, "json-stringify-safe": { @@ -3512,13 +3175,38 @@ "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", "dev": true }, + "just-extend": { + "version": "1.1.27", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", + "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==", + "dev": true + }, + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } }, "latest-version": { @@ -3527,7 +3215,7 @@ "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", "dev": true, "requires": { - "package-json": "4.0.1" + "package-json": "^4.0.0" } }, "lazy-cache": { @@ -3549,8 +3237,8 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" } }, "lodash": { @@ -3564,8 +3252,8 @@ "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", "dev": true, "requires": { - "lodash._basecopy": "3.0.1", - "lodash.keys": "3.1.2" + "lodash._basecopy": "^3.0.0", + "lodash.keys": "^3.0.0" } }, "lodash._basecopy": { @@ -3592,9 +3280,9 @@ "integrity": "sha1-g4pbri/aymOsIt7o4Z+k5taXCxE=", "dev": true, "requires": { - "lodash._bindcallback": "3.0.1", - "lodash._isiterateecall": "3.0.9", - "lodash.restparam": "3.6.1" + "lodash._bindcallback": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash.restparam": "^3.0.0" } }, "lodash._getnative": { @@ -3615,9 +3303,9 @@ "integrity": "sha1-POnwI0tLIiPilrj6CsH+6OvKZPo=", "dev": true, "requires": { - "lodash._baseassign": "3.2.0", - "lodash._createassigner": "3.1.1", - "lodash.keys": "3.1.2" + "lodash._baseassign": "^3.0.0", + "lodash._createassigner": "^3.0.0", + "lodash.keys": "^3.0.0" } }, "lodash.bind": { @@ -3625,6 +3313,11 @@ "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=" }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, "lodash.clone": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", @@ -3647,9 +3340,9 @@ "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", "dev": true, "requires": { - "lodash._baseassign": "3.2.0", - "lodash._basecreate": "3.0.3", - "lodash._isiterateecall": "3.0.9" + "lodash._baseassign": "^3.0.0", + "lodash._basecreate": "^3.0.0", + "lodash._isiterateecall": "^3.0.0" } }, "lodash.defaults": { @@ -3658,8 +3351,8 @@ "integrity": "sha1-xzCLGNv4vJNy1wGnNJPGEZK9Liw=", "dev": true, "requires": { - "lodash.assign": "3.2.0", - "lodash.restparam": "3.6.1" + "lodash.assign": "^3.0.0", + "lodash.restparam": "^3.0.0" } }, "lodash.difference": { @@ -3695,6 +3388,12 @@ "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=" }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, "lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", @@ -3718,11 +3417,16 @@ "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", "dev": true, "requires": { - "lodash._getnative": "3.9.1", - "lodash.isarguments": "3.1.0", - "lodash.isarray": "3.0.4" + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" } }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha1-VYqlO0O2YeGSWgr9+japoQhf5Xo=" + }, "lodash.noop": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash.noop/-/lodash.noop-3.0.1.tgz", @@ -3766,16 +3470,22 @@ "dev": true }, "lolex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz", - "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE=", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.1.tgz", + "integrity": "sha512-mQuW55GhduF3ppo+ZRUTz1PRjEh1hS5BbqU7d8D0ez2OKxHDod7StPPeAVKisZR5aLkHZjdGWSL42LSONUJsZw==", "dev": true }, + "long": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/long/-/long-2.4.0.tgz", + "integrity": "sha1-n6GAux2VAM3CnEFWdmoZleH0Uk8=" + }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true + "dev": true, + "optional": true }, "lowercase-keys": { "version": "1.0.0", @@ -3789,8 +3499,8 @@ "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", "dev": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, "lsmod": { @@ -3804,7 +3514,7 @@ "integrity": "sha512-0Pkui4wLJ7rxvmfUvs87skoEaxmu0hCUApF8nonzpl7q//FWp9zu8W61Scz4sd/kUiqDxvUhtoam2efDyiBzcA==", "dev": true, "requires": { - "pify": "3.0.0" + "pify": "^3.0.0" }, "dependencies": { "pify": { @@ -3842,19 +3552,19 @@ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.4" + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" } }, "mime": { @@ -3872,7 +3582,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.12.tgz", "integrity": "sha1-FSuiVndwIN1GY/VMLnvCY4HnFyk=", "requires": { - "mime-db": "1.24.0" + "mime-db": "~1.24.0" } }, "minimatch": { @@ -3881,7 +3591,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.8" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -3934,12 +3644,12 @@ "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.1", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "ms": { @@ -3954,21 +3664,26 @@ "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", "dev": true, "requires": { - "has-flag": "1.0.0" + "has-flag": "^1.0.0" } } } }, + "module-details-from-path": { + "version": "1.0.3", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=" + }, "morgan": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.7.0.tgz", "integrity": "sha1-6xDKjlDRq+D409rVwCAdBS2YHGI=", "requires": { - "basic-auth": "1.0.4", - "debug": "2.2.0", - "depd": "1.1.0", - "on-finished": "2.3.0", - "on-headers": "1.0.1" + "basic-auth": "~1.0.3", + "debug": "~2.2.0", + "depd": "~1.1.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.1" } }, "ms": { @@ -3989,9 +3704,9 @@ "dev": true }, "nan": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz", - "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=", + "version": "2.14.2", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/nan/-/nan-2.14.2.tgz", + "integrity": "sha1-9TdkAGlRaPTMaUrJOT0MlYXu6hk=", "dev": true, "optional": true }, @@ -4006,22 +3721,68 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" }, + "nise": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.2.0.tgz", + "integrity": "sha512-q9jXh3UNsMV28KeqI43ILz5+c3l+RiNW8mhurEwCKckuHQbL+hTJIKKTiUlCPKlgQ/OukFvSnKB/Jk3+sFbkGA==", + "dev": true, + "requires": { + "formatio": "^1.2.0", + "just-extend": "^1.1.26", + "lolex": "^1.6.0", + "path-to-regexp": "^1.7.0", + "text-encoding": "^0.6.4" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "lolex": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz", + "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=", + "dev": true + }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + } + } + }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=" + }, "nodemon": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.12.1.tgz", "integrity": "sha1-mWpW3EnZ8Wu/G3ik3gjxNjSzh40=", "dev": true, "requires": { - "chokidar": "1.7.0", - "debug": "2.6.9", - "es6-promise": "3.3.1", - "ignore-by-default": "1.0.1", - "lodash.defaults": "3.1.2", - "minimatch": "3.0.4", - "ps-tree": "1.1.0", - "touch": "3.1.0", + "chokidar": "^1.7.0", + "debug": "^2.6.8", + "es6-promise": "^3.3.1", + "ignore-by-default": "^1.0.1", + "lodash.defaults": "^3.1.2", + "minimatch": "^3.0.4", + "ps-tree": "^1.1.0", + "touch": "^3.1.0", "undefsafe": "0.0.3", - "update-notifier": "2.3.0" + "update-notifier": "^2.2.0" }, "dependencies": { "debug": { @@ -4047,7 +3808,7 @@ "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "dev": true, "requires": { - "abbrev": "1.0.9" + "abbrev": "1" } }, "normalize-path": { @@ -4056,7 +3817,7 @@ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "requires": { - "remove-trailing-separator": "1.1.0" + "remove-trailing-separator": "^1.0.1" } }, "npm-run-path": { @@ -4065,7 +3826,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "number-is-nan": { @@ -4080,33 +3841,33 @@ "integrity": "sha512-oUu0WHt1k/JMIODvAYXX6C50Mupw2GO34P/Jdg2ty9xrLufBthHiKR2gf08aF+9S0abW1fl24R7iKRBXzibZmg==", "dev": true, "requires": { - "archy": "1.0.0", - "arrify": "1.0.1", - "caching-transform": "1.0.1", - "convert-source-map": "1.5.0", - "debug-log": "1.0.1", - "default-require-extensions": "1.0.0", - "find-cache-dir": "0.1.1", - "find-up": "2.1.0", - "foreground-child": "1.5.6", - "glob": "7.1.2", - "istanbul-lib-coverage": "1.1.1", - "istanbul-lib-hook": "1.1.0", - "istanbul-lib-instrument": "1.9.1", - "istanbul-lib-report": "1.1.2", - "istanbul-lib-source-maps": "1.2.2", - "istanbul-reports": "1.1.3", - "md5-hex": "1.3.0", - "merge-source-map": "1.0.4", - "micromatch": "2.3.11", - "mkdirp": "0.5.1", - "resolve-from": "2.0.0", - "rimraf": "2.6.2", - "signal-exit": "3.0.2", - "spawn-wrap": "1.3.8", - "test-exclude": "4.1.1", - "yargs": "10.0.3", - "yargs-parser": "8.0.0" + "archy": "^1.0.0", + "arrify": "^1.0.1", + "caching-transform": "^1.0.0", + "convert-source-map": "^1.3.0", + "debug-log": "^1.0.1", + "default-require-extensions": "^1.0.0", + "find-cache-dir": "^0.1.1", + "find-up": "^2.1.0", + "foreground-child": "^1.5.3", + "glob": "^7.0.6", + "istanbul-lib-coverage": "^1.1.1", + "istanbul-lib-hook": "^1.1.0", + "istanbul-lib-instrument": "^1.9.1", + "istanbul-lib-report": "^1.1.2", + "istanbul-lib-source-maps": "^1.2.2", + "istanbul-reports": "^1.1.3", + "md5-hex": "^1.2.0", + "merge-source-map": "^1.0.2", + "micromatch": "^2.3.11", + "mkdirp": "^0.5.0", + "resolve-from": "^2.0.0", + "rimraf": "^2.5.4", + "signal-exit": "^3.0.1", + "spawn-wrap": "=1.3.8", + "test-exclude": "^4.1.1", + "yargs": "^10.0.3", + "yargs-parser": "^8.0.0" }, "dependencies": { "align-text": { @@ -4114,10 +3875,11 @@ "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, + "optional": true, "requires": { - "kind-of": "3.2.2", - "longest": "1.0.1", - "repeat-string": "1.6.1" + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" } }, "amdefine": { @@ -4144,7 +3906,7 @@ "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", "dev": true, "requires": { - "default-require-extensions": "1.0.0" + "default-require-extensions": "^1.0.0" } }, "archy": { @@ -4159,7 +3921,7 @@ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, "requires": { - "arr-flatten": "1.1.0" + "arr-flatten": "^1.0.1" } }, "arr-flatten": { @@ -4192,9 +3954,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" } }, "babel-generator": { @@ -4203,14 +3965,14 @@ "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=", "dev": true, "requires": { - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "detect-indent": "4.0.0", - "jsesc": "1.3.0", - "lodash": "4.17.4", - "source-map": "0.5.7", - "trim-right": "1.0.1" + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.6", + "trim-right": "^1.0.1" } }, "babel-messages": { @@ -4219,7 +3981,7 @@ "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "dev": true, "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" } }, "babel-runtime": { @@ -4228,8 +3990,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babel-template": { @@ -4238,11 +4000,11 @@ "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "lodash": "4.17.4" + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" } }, "babel-traverse": { @@ -4251,15 +4013,15 @@ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.2", - "lodash": "4.17.4" + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" } }, "babel-types": { @@ -4268,10 +4030,10 @@ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.4", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" } }, "babylon": { @@ -4292,7 +4054,7 @@ "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -4302,9 +4064,9 @@ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.2" + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" } }, "builtin-modules": { @@ -4319,9 +4081,9 @@ "integrity": "sha1-bb2y8g+Nj7znnz6U6dF0Lc31wKE=", "dev": true, "requires": { - "md5-hex": "1.3.0", - "mkdirp": "0.5.1", - "write-file-atomic": "1.3.4" + "md5-hex": "^1.2.0", + "mkdirp": "^0.5.1", + "write-file-atomic": "^1.1.4" } }, "camelcase": { @@ -4338,8 +4100,8 @@ "dev": true, "optional": true, "requires": { - "align-text": "0.1.4", - "lazy-cache": "1.0.4" + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" } }, "chalk": { @@ -4348,11 +4110,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "cliui": { @@ -4362,8 +4124,8 @@ "dev": true, "optional": true, "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", + "center-align": "^0.1.1", + "right-align": "^0.1.1", "wordwrap": "0.0.2" }, "dependencies": { @@ -4412,8 +4174,8 @@ "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", "dev": true, "requires": { - "lru-cache": "4.1.1", - "which": "1.3.0" + "lru-cache": "^4.0.1", + "which": "^1.2.9" } }, "debug": { @@ -4443,7 +4205,7 @@ "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", "dev": true, "requires": { - "strip-bom": "2.0.0" + "strip-bom": "^2.0.0" } }, "detect-indent": { @@ -4452,7 +4214,7 @@ "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", "dev": true, "requires": { - "repeating": "2.0.1" + "repeating": "^2.0.0" } }, "error-ex": { @@ -4461,7 +4223,7 @@ "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true, "requires": { - "is-arrayish": "0.2.1" + "is-arrayish": "^0.2.1" } }, "escape-string-regexp": { @@ -4482,13 +4244,13 @@ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" }, "dependencies": { "cross-spawn": { @@ -4497,9 +4259,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.1", - "shebang-command": "1.2.0", - "which": "1.3.0" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } } } @@ -4510,7 +4272,7 @@ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, "requires": { - "is-posix-bracket": "0.1.1" + "is-posix-bracket": "^0.1.0" } }, "expand-range": { @@ -4519,7 +4281,7 @@ "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", "dev": true, "requires": { - "fill-range": "2.2.3" + "fill-range": "^2.1.0" } }, "extglob": { @@ -4528,7 +4290,7 @@ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "filename-regex": { @@ -4543,11 +4305,11 @@ "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", "dev": true, "requires": { - "is-number": "2.1.0", - "isobject": "2.1.0", - "randomatic": "1.1.7", - "repeat-element": "1.1.2", - "repeat-string": "1.6.1" + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^1.1.3", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" } }, "find-cache-dir": { @@ -4556,9 +4318,9 @@ "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", "dev": true, "requires": { - "commondir": "1.0.1", - "mkdirp": "0.5.1", - "pkg-dir": "1.0.0" + "commondir": "^1.0.1", + "mkdirp": "^0.5.1", + "pkg-dir": "^1.0.0" } }, "find-up": { @@ -4567,7 +4329,7 @@ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "locate-path": "2.0.0" + "locate-path": "^2.0.0" } }, "for-in": { @@ -4582,7 +4344,7 @@ "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", "dev": true, "requires": { - "for-in": "1.0.2" + "for-in": "^1.0.1" } }, "foreground-child": { @@ -4591,8 +4353,8 @@ "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", "dev": true, "requires": { - "cross-spawn": "4.0.2", - "signal-exit": "3.0.2" + "cross-spawn": "^4", + "signal-exit": "^3.0.0" } }, "fs.realpath": { @@ -4619,12 +4381,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "glob-base": { @@ -4633,8 +4395,8 @@ "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", "dev": true, "requires": { - "glob-parent": "2.0.0", - "is-glob": "2.0.1" + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" } }, "glob-parent": { @@ -4643,7 +4405,7 @@ "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", "dev": true, "requires": { - "is-glob": "2.0.1" + "is-glob": "^2.0.0" } }, "globals": { @@ -4664,10 +4426,10 @@ "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", "dev": true, "requires": { - "async": "1.5.2", - "optimist": "0.6.1", - "source-map": "0.4.4", - "uglify-js": "2.8.29" + "async": "^1.4.0", + "optimist": "^0.6.1", + "source-map": "^0.4.4", + "uglify-js": "^2.6" }, "dependencies": { "source-map": { @@ -4676,7 +4438,7 @@ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } } } @@ -4687,7 +4449,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "has-flag": { @@ -4714,8 +4476,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -4730,7 +4492,7 @@ "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", "dev": true, "requires": { - "loose-envify": "1.3.1" + "loose-envify": "^1.0.0" } }, "invert-kv": { @@ -4757,7 +4519,7 @@ "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { - "builtin-modules": "1.1.1" + "builtin-modules": "^1.0.0" } }, "is-dotfile": { @@ -4772,7 +4534,7 @@ "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", "dev": true, "requires": { - "is-primitive": "2.0.0" + "is-primitive": "^2.0.0" } }, "is-extendable": { @@ -4793,7 +4555,7 @@ "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-fullwidth-code-point": { @@ -4802,7 +4564,7 @@ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-glob": { @@ -4811,7 +4573,7 @@ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "is-number": { @@ -4820,7 +4582,7 @@ "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } }, "is-posix-bracket": { @@ -4880,7 +4642,7 @@ "integrity": "sha512-U3qEgwVDUerZ0bt8cfl3dSP3S6opBoOtk3ROO5f2EfBr/SRiD9FQqzwaZBqFORu8W7O0EXpai+k7kxHK13beRg==", "dev": true, "requires": { - "append-transform": "0.4.0" + "append-transform": "^0.4.0" } }, "istanbul-lib-instrument": { @@ -4889,13 +4651,13 @@ "integrity": "sha512-RQmXeQ7sphar7k7O1wTNzVczF9igKpaeGQAG9qR2L+BS4DCJNTI9nytRmIVYevwO0bbq+2CXvJmYDuz0gMrywA==", "dev": true, "requires": { - "babel-generator": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "istanbul-lib-coverage": "1.1.1", - "semver": "5.4.1" + "babel-generator": "^6.18.0", + "babel-template": "^6.16.0", + "babel-traverse": "^6.18.0", + "babel-types": "^6.18.0", + "babylon": "^6.18.0", + "istanbul-lib-coverage": "^1.1.1", + "semver": "^5.3.0" } }, "istanbul-lib-report": { @@ -4904,10 +4666,10 @@ "integrity": "sha512-UTv4VGx+HZivJQwAo1wnRwe1KTvFpfi/NYwN7DcsrdzMXwpRT/Yb6r4SBPoHWj4VuQPakR32g4PUUeyKkdDkBA==", "dev": true, "requires": { - "istanbul-lib-coverage": "1.1.1", - "mkdirp": "0.5.1", - "path-parse": "1.0.5", - "supports-color": "3.2.3" + "istanbul-lib-coverage": "^1.1.1", + "mkdirp": "^0.5.1", + "path-parse": "^1.0.5", + "supports-color": "^3.1.2" }, "dependencies": { "supports-color": { @@ -4916,7 +4678,7 @@ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, "requires": { - "has-flag": "1.0.0" + "has-flag": "^1.0.0" } } } @@ -4927,11 +4689,11 @@ "integrity": "sha512-8BfdqSfEdtip7/wo1RnrvLpHVEd8zMZEDmOFEnpC6dg0vXflHt9nvoAyQUzig2uMSXfF2OBEYBV3CVjIL9JvaQ==", "dev": true, "requires": { - "debug": "3.1.0", - "istanbul-lib-coverage": "1.1.1", - "mkdirp": "0.5.1", - "rimraf": "2.6.2", - "source-map": "0.5.7" + "debug": "^3.1.0", + "istanbul-lib-coverage": "^1.1.1", + "mkdirp": "^0.5.1", + "rimraf": "^2.6.1", + "source-map": "^0.5.3" }, "dependencies": { "debug": { @@ -4951,7 +4713,7 @@ "integrity": "sha512-ZEelkHh8hrZNI5xDaKwPMFwDsUf5wIEI2bXAFGp1e6deR2mnEKBPhLJEgr4ZBt8Gi6Mj38E/C8kcy9XLggVO2Q==", "dev": true, "requires": { - "handlebars": "4.0.11" + "handlebars": "^4.0.3" } }, "js-tokens": { @@ -4972,7 +4734,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.5" + "is-buffer": "^1.1.5" } }, "lazy-cache": { @@ -4988,7 +4750,7 @@ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { - "invert-kv": "1.0.0" + "invert-kv": "^1.0.0" } }, "load-json-file": { @@ -4997,11 +4759,11 @@ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" } }, "locate-path": { @@ -5010,8 +4772,8 @@ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" }, "dependencies": { "path-exists": { @@ -5032,7 +4794,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true + "dev": true, + "optional": true }, "loose-envify": { "version": "1.3.1", @@ -5040,7 +4803,7 @@ "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "dev": true, "requires": { - "js-tokens": "3.0.2" + "js-tokens": "^3.0.0" } }, "lru-cache": { @@ -5049,8 +4812,8 @@ "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", "dev": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, "md5-hex": { @@ -5059,7 +4822,7 @@ "integrity": "sha1-0sSv6YPENwZiF5uMrRRSGRNQRsQ=", "dev": true, "requires": { - "md5-o-matic": "0.1.1" + "md5-o-matic": "^0.1.1" } }, "md5-o-matic": { @@ -5074,7 +4837,7 @@ "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { - "mimic-fn": "1.1.0" + "mimic-fn": "^1.0.0" } }, "merge-source-map": { @@ -5083,7 +4846,7 @@ "integrity": "sha1-pd5GU42uhNQRTMXqArR3KmNGcB8=", "dev": true, "requires": { - "source-map": "0.5.7" + "source-map": "^0.5.6" } }, "micromatch": { @@ -5092,19 +4855,19 @@ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.4" + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" } }, "mimic-fn": { @@ -5119,7 +4882,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.8" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -5149,10 +4912,10 @@ "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "dev": true, "requires": { - "hosted-git-info": "2.5.0", - "is-builtin-module": "1.0.0", - "semver": "5.4.1", - "validate-npm-package-license": "3.0.1" + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, "normalize-path": { @@ -5161,7 +4924,7 @@ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "requires": { - "remove-trailing-separator": "1.1.0" + "remove-trailing-separator": "^1.0.1" } }, "npm-run-path": { @@ -5170,7 +4933,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "number-is-nan": { @@ -5191,8 +4954,8 @@ "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", "dev": true, "requires": { - "for-own": "0.1.5", - "is-extendable": "0.1.1" + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" } }, "once": { @@ -5201,7 +4964,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "optimist": { @@ -5210,8 +4973,8 @@ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { - "minimist": "0.0.8", - "wordwrap": "0.0.3" + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" } }, "os-homedir": { @@ -5226,9 +4989,9 @@ "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { - "execa": "0.7.0", - "lcid": "1.0.0", - "mem": "1.1.0" + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" } }, "p-finally": { @@ -5249,7 +5012,7 @@ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { - "p-limit": "1.1.0" + "p-limit": "^1.1.0" } }, "parse-glob": { @@ -5258,10 +5021,10 @@ "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", "dev": true, "requires": { - "glob-base": "0.3.0", - "is-dotfile": "1.0.3", - "is-extglob": "1.0.0", - "is-glob": "2.0.1" + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" } }, "parse-json": { @@ -5270,7 +5033,7 @@ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { - "error-ex": "1.3.1" + "error-ex": "^1.2.0" } }, "path-exists": { @@ -5279,7 +5042,7 @@ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { - "pinkie-promise": "2.0.1" + "pinkie-promise": "^2.0.0" } }, "path-is-absolute": { @@ -5306,9 +5069,9 @@ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "pify": { @@ -5329,7 +5092,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "pkg-dir": { @@ -5338,7 +5101,7 @@ "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", "dev": true, "requires": { - "find-up": "1.1.2" + "find-up": "^1.0.0" }, "dependencies": { "find-up": { @@ -5347,8 +5110,8 @@ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } } } @@ -5371,8 +5134,8 @@ "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", "dev": true, "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { "is-number": { @@ -5381,7 +5144,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -5390,7 +5153,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.5" + "is-buffer": "^1.1.5" } } } @@ -5401,7 +5164,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "1.1.5" + "is-buffer": "^1.1.5" } } } @@ -5412,9 +5175,9 @@ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.4.0", - "path-type": "1.1.0" + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" } }, "read-pkg-up": { @@ -5423,8 +5186,8 @@ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" }, "dependencies": { "find-up": { @@ -5433,8 +5196,8 @@ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } } } @@ -5451,7 +5214,7 @@ "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", "dev": true, "requires": { - "is-equal-shallow": "0.1.3" + "is-equal-shallow": "^0.1.3" } }, "remove-trailing-separator": { @@ -5478,7 +5241,7 @@ "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "dev": true, "requires": { - "is-finite": "1.0.2" + "is-finite": "^1.0.0" } }, "require-directory": { @@ -5506,7 +5269,7 @@ "dev": true, "optional": true, "requires": { - "align-text": "0.1.4" + "align-text": "^0.1.1" } }, "rimraf": { @@ -5515,7 +5278,7 @@ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } }, "semver": { @@ -5536,7 +5299,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -5569,12 +5332,12 @@ "integrity": "sha512-Yfkd7Yiwz4RcBPrDWzvhnTzQINBHNqOEhUzOdWZ67Y9b4wzs3Gz6ymuptQmRBpzlpOzroM7jwzmBdRec7JJ0UA==", "dev": true, "requires": { - "foreground-child": "1.5.6", - "mkdirp": "0.5.1", - "os-homedir": "1.0.2", - "rimraf": "2.6.2", - "signal-exit": "3.0.2", - "which": "1.3.0" + "foreground-child": "^1.5.6", + "mkdirp": "^0.5.0", + "os-homedir": "^1.0.1", + "rimraf": "^2.3.3", + "signal-exit": "^3.0.2", + "which": "^1.2.4" } }, "spdx-correct": { @@ -5583,7 +5346,7 @@ "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", "dev": true, "requires": { - "spdx-license-ids": "1.2.2" + "spdx-license-ids": "^1.0.2" } }, "spdx-expression-parse": { @@ -5604,8 +5367,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" }, "dependencies": { "ansi-regex": { @@ -5626,7 +5389,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } } } @@ -5637,7 +5400,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-bom": { @@ -5646,7 +5409,7 @@ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { - "is-utf8": "0.2.1" + "is-utf8": "^0.2.0" } }, "strip-eof": { @@ -5667,11 +5430,11 @@ "integrity": "sha512-35+Asrsk3XHJDBgf/VRFexPgh3UyETv8IAn/LRTiZjVy6rjPVqdEk8dJcJYBzl1w0XCJM48lvTy8SfEsCWS4nA==", "dev": true, "requires": { - "arrify": "1.0.1", - "micromatch": "2.3.11", - "object-assign": "4.1.1", - "read-pkg-up": "1.0.1", - "require-main-filename": "1.0.1" + "arrify": "^1.0.1", + "micromatch": "^2.3.11", + "object-assign": "^4.1.0", + "read-pkg-up": "^1.0.1", + "require-main-filename": "^1.0.1" } }, "to-fast-properties": { @@ -5693,9 +5456,9 @@ "dev": true, "optional": true, "requires": { - "source-map": "0.5.7", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" }, "dependencies": { "yargs": { @@ -5705,9 +5468,9 @@ "dev": true, "optional": true, "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", "window-size": "0.1.0" } } @@ -5726,8 +5489,8 @@ "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", "dev": true, "requires": { - "spdx-correct": "1.0.2", - "spdx-expression-parse": "1.0.4" + "spdx-correct": "~1.0.0", + "spdx-expression-parse": "~1.0.0" } }, "which": { @@ -5736,7 +5499,7 @@ "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "which-module": { @@ -5764,8 +5527,8 @@ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" }, "dependencies": { "string-width": { @@ -5774,9 +5537,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } } } @@ -5793,9 +5556,9 @@ "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "imurmurhash": "0.1.4", - "slide": "1.1.6" + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "slide": "^1.1.5" } }, "y18n": { @@ -5816,18 +5579,18 @@ "integrity": "sha512-DqBpQ8NAUX4GyPP/ijDGHsJya4tYqLQrjPr95HNsr1YwL3+daCfvBwg7+gIC6IdJhR2kATh3hb61vjzMWEtjdw==", "dev": true, "requires": { - "cliui": "3.2.0", - "decamelize": "1.2.0", - "find-up": "2.1.0", - "get-caller-file": "1.0.2", - "os-locale": "2.1.0", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", - "y18n": "3.2.1", - "yargs-parser": "8.0.0" + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^8.0.0" }, "dependencies": { "cliui": { @@ -5836,9 +5599,9 @@ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "dev": true, "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wrap-ansi": "2.1.0" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" }, "dependencies": { "string-width": { @@ -5847,9 +5610,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } } } @@ -5862,7 +5625,7 @@ "integrity": "sha1-IdR2Mw5agieaS4gTRb8GYQLiGcY=", "dev": true, "requires": { - "camelcase": "4.1.0" + "camelcase": "^4.1.0" }, "dependencies": { "camelcase": { @@ -5898,9 +5661,9 @@ "integrity": "sha1-scnMBE7xuf5jYG/BQau7MuFHMMw=", "dev": true, "requires": { - "define-properties": "1.1.2", - "function-bind": "1.1.1", - "object-keys": "1.0.11" + "define-properties": "^1.1.2", + "function-bind": "^1.1.0", + "object-keys": "^1.0.10" } }, "object.omit": { @@ -5909,8 +5672,8 @@ "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", "dev": true, "requires": { - "for-own": "0.1.5", - "is-extendable": "0.1.1" + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" } }, "on-finished": { @@ -5931,7 +5694,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "onetime": { @@ -5940,14 +5703,19 @@ "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", "dev": true }, + "opentracing": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/opentracing/-/opentracing-0.14.4.tgz", + "integrity": "sha512-nNnZDkUNExBwEpb7LZaeMeQgvrlO8l4bgY/LvGNZCR0xG/dGWqHqjKrAmR5GUoYo0FIz38kxasvA1aevxWs2CA==" + }, "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { - "minimist": "0.0.8", - "wordwrap": "0.0.3" + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" }, "dependencies": { "wordwrap": { @@ -5964,12 +5732,12 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" } }, "os-homedir": { @@ -5990,10 +5758,10 @@ "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", "dev": true, "requires": { - "got": "6.7.1", - "registry-auth-token": "3.3.1", - "registry-url": "3.1.0", - "semver": "5.4.1" + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" } }, "parse-glob": { @@ -6002,10 +5770,10 @@ "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", "dev": true, "requires": { - "glob-base": "0.3.0", - "is-dotfile": "1.0.3", - "is-extglob": "1.0.0", - "is-glob": "2.0.1" + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" } }, "parseurl": { @@ -6019,7 +5787,7 @@ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { - "pinkie-promise": "2.0.1" + "pinkie-promise": "^2.0.0" } }, "path-is-absolute": { @@ -6057,7 +5825,7 @@ "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", "dev": true, "requires": { - "through": "2.3.8" + "through": "~2.3" } }, "performance-now": { @@ -6083,7 +5851,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "pkg-dir": { @@ -6092,7 +5860,7 @@ "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", "dev": true, "requires": { - "find-up": "1.1.2" + "find-up": "^1.0.0" } }, "pkg-up": { @@ -6101,7 +5869,7 @@ "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=", "dev": true, "requires": { - "find-up": "1.1.2" + "find-up": "^1.0.0" } }, "pkginfo": { @@ -6133,6 +5901,11 @@ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", "dev": true }, + "process": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/process/-/process-0.10.1.tgz", + "integrity": "sha1-hCRXzFHP7XLcd1r+6vuMYDQ3JyU=" + }, "process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", @@ -6145,12 +5918,47 @@ "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", "dev": true }, + "prom-client": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-11.5.3.tgz", + "integrity": "sha512-iz22FmTbtkyL2vt0MdDFY+kWof+S9UB/NACxSn2aJcewtw+EERsen0urSkZ2WrHseNdydsvcxCTAnPcSMZZv4Q==", + "requires": { + "tdigest": "^0.1.1" + } + }, + "protobufjs": { + "version": "6.11.2", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/protobufjs/-/protobufjs-6.11.2.tgz", + "integrity": "sha1-3jn6vU7TK+qgjpux4w0IVEwe34s=", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "dependencies": { + "long": { + "version": "4.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/long/-/long-4.0.0.tgz", + "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=" + } + } + }, "proxy-addr": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.2.tgz", "integrity": "sha1-tMxfImENlTWCTBI675089zxAujc=", "requires": { - "forwarded": "0.1.0", + "forwarded": "~0.1.0", "ipaddr.js": "1.1.1" } }, @@ -6160,7 +5968,7 @@ "integrity": "sha1-tCGyQUDWID8e08dplrRCewjowBQ=", "dev": true, "requires": { - "event-stream": "3.3.4" + "event-stream": "~3.3.0" } }, "pseudomap": { @@ -6185,8 +5993,8 @@ "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", "dev": true, "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { "is-number": { @@ -6195,7 +6003,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -6204,7 +6012,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -6215,7 +6023,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -6260,10 +6068,10 @@ "integrity": "sha1-2M6ctX6NZNnHut2YdsfDTL48cHc=", "dev": true, "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "~0.4.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, "dependencies": { "minimist": { @@ -6280,13 +6088,13 @@ "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.0.3", + "util-deprecate": "~1.0.1" }, "dependencies": { "inherits": { @@ -6303,10 +6111,10 @@ "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "minimatch": "3.0.4", - "readable-stream": "2.3.3", - "set-immediate-shim": "1.0.1" + "graceful-fs": "^4.1.2", + "minimatch": "^3.0.2", + "readable-stream": "^2.0.2", + "set-immediate-shim": "^1.0.1" } }, "readline2": { @@ -6315,8 +6123,8 @@ "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", "mute-stream": "0.0.5" } }, @@ -6326,7 +6134,7 @@ "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", "dev": true, "requires": { - "resolve": "1.5.0" + "resolve": "^1.1.6" } }, "redis-commands": { @@ -6345,7 +6153,7 @@ "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", "dev": true, "requires": { - "is-equal-shallow": "0.1.3" + "is-equal-shallow": "^0.1.3" } }, "registry-auth-token": { @@ -6354,8 +6162,8 @@ "integrity": "sha1-+w0yie4Nmtosu1KvXf5mywcNMAY=", "dev": true, "requires": { - "rc": "1.2.2", - "safe-buffer": "5.1.1" + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" } }, "registry-url": { @@ -6364,7 +6172,7 @@ "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", "dev": true, "requires": { - "rc": "1.2.2" + "rc": "^1.0.1" } }, "remove-trailing-separator": { @@ -6390,28 +6198,28 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.5.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.0", - "forever-agent": "0.6.1", - "form-data": "2.1.1", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.12", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.0.1" + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.1.1", + "har-validator": "~4.2.1", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "oauth-sign": "~0.8.1", + "performance-now": "^0.2.0", + "qs": "~6.4.0", + "safe-buffer": "^5.0.1", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.0.0" }, "dependencies": { "caseless": { @@ -6424,8 +6232,8 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" + "ajv": "^4.9.1", + "har-schema": "^1.0.5" } }, "qs": { @@ -6438,7 +6246,51 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "^5.0.1" + } + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-in-the-middle": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.1.0.tgz", + "integrity": "sha512-M2rLKVupQfJ5lf9OvqFGIT+9iVLnTmjgbOmpil12hiSQNn5zJTKGPoIisETNjfK+09vP3rpm1zJajmErpr2sEQ==", + "requires": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.12.0" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" } } } @@ -6449,8 +6301,8 @@ "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "dev": true, "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" } }, "requires-port": { @@ -6465,7 +6317,7 @@ "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", "dev": true, "requires": { - "path-parse": "1.0.5" + "path-parse": "^1.0.5" } }, "resolve-from": { @@ -6480,8 +6332,8 @@ "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", "dev": true, "requires": { - "exit-hook": "1.1.1", - "onetime": "1.1.0" + "exit-hook": "^1.0.0", + "onetime": "^1.0.0" } }, "right-align": { @@ -6491,7 +6343,7 @@ "dev": true, "optional": true, "requires": { - "align-text": "0.1.4" + "align-text": "^0.1.1" } }, "rimraf": { @@ -6500,7 +6352,7 @@ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } }, "run-async": { @@ -6509,7 +6361,7 @@ "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", "dev": true, "requires": { - "once": "1.4.0" + "once": "^1.3.0" } }, "rx-lite": { @@ -6524,9 +6376,9 @@ "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, "samsam": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz", - "integrity": "sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc=", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", + "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", "dev": true }, "semver": { @@ -6541,7 +6393,7 @@ "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", "dev": true, "requires": { - "semver": "5.4.1" + "semver": "^5.0.3" } }, "send": { @@ -6549,19 +6401,19 @@ "resolved": "https://registry.npmjs.org/send/-/send-0.14.1.tgz", "integrity": "sha1-qVSYQyU5L1FTKndgdg5FlZjIn3o=", "requires": { - "debug": "2.2.0", - "depd": "1.1.0", - "destroy": "1.0.4", - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "etag": "1.7.0", + "debug": "~2.2.0", + "depd": "~1.1.0", + "destroy": "~1.0.4", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "etag": "~1.7.0", "fresh": "0.3.0", - "http-errors": "1.5.0", + "http-errors": "~1.5.0", "mime": "1.3.4", "ms": "0.7.1", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.3.0" + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.3.0" } }, "serve-static": { @@ -6569,9 +6421,9 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.11.1.tgz", "integrity": "sha1-1sznaTUF9zPHWd5Xvvwa92wPCAU=", "requires": { - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "parseurl": "1.3.1", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "parseurl": "~1.3.1", "send": "0.14.1" } }, @@ -6592,7 +6444,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -6607,10 +6459,10 @@ "integrity": "sha1-lSxE4LHtkBPvU5WBecxkPod3Rms=", "dev": true, "requires": { - "array-filter": "0.0.1", - "array-map": "0.0.0", - "array-reduce": "0.0.0", - "jsonify": "0.0.0" + "array-filter": "~0.0.0", + "array-map": "~0.0.0", + "array-reduce": "~0.0.0", + "jsonify": "~0.0.0" } }, "shelljs": { @@ -6619,11 +6471,16 @@ "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", "dev": true, "requires": { - "glob": "7.1.2", - "interpret": "1.0.4", - "rechoir": "0.6.2" + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" } }, + "shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -6631,15 +6488,41 @@ "dev": true }, "sinon": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz", - "integrity": "sha1-RUKk9JugxFwF6y6d2dID4rjv4L8=", - "dev": true, - "requires": { - "formatio": "1.1.1", - "lolex": "1.3.2", - "samsam": "1.1.2", - "util": "0.10.3" + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.1.3.tgz", + "integrity": "sha512-c7u0ZuvBRX1eXuB4jN3BRCAOGiUTlM8SE3TxbJHrNiHUKL7wonujMOB6Fi1gQc00U91IscFORQHDga/eccqpbw==", + "dev": true, + "requires": { + "diff": "^3.1.0", + "formatio": "1.2.0", + "lodash.get": "^4.4.2", + "lolex": "^2.2.0", + "nise": "^1.2.0", + "supports-color": "^4.4.0", + "type-detect": "^4.0.5" + }, + "dependencies": { + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "^2.0.0" + } + }, + "type-detect": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.5.tgz", + "integrity": "sha512-N9IvkQslUGYGC24RkJk1ba99foK6TkwC2FHAEBlQFBP0RxQZS8ZpJuAZcwiY/w9ZJHFQb1aOXBI60OdxhTrwEQ==", + "dev": true + } } }, "slice-ansi": { @@ -6653,7 +6536,7 @@ "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", "requires": { - "hoek": "2.16.3" + "hoek": "2.x.x" } }, "source-map": { @@ -6663,7 +6546,7 @@ "dev": true, "optional": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } }, "split": { @@ -6672,7 +6555,7 @@ "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", "dev": true, "requires": { - "through": "2.3.8" + "through": "2" } }, "sprintf-js": { @@ -6686,15 +6569,15 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.10.1.tgz", "integrity": "sha1-MOGl0ykkSXShr2FREznVla9mOLA=", "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.0", - "dashdash": "1.14.0", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.6", - "jodid25519": "1.0.2", - "jsbn": "0.1.0", - "tweetnacl": "0.14.3" + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jodid25519": "^1.0.0", + "jsbn": "~0.1.0", + "tweetnacl": "~0.14.0" }, "dependencies": { "assert-plus": { @@ -6720,18 +6603,23 @@ "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", "dev": true, "requires": { - "duplexer": "0.1.1" + "duplexer": "~0.1.1" } }, + "string-template": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", + "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=" + }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { @@ -6740,7 +6628,7 @@ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "stringstream": { @@ -6754,7 +6642,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-bom": { @@ -6781,7 +6669,7 @@ "integrity": "sha1-HGYfZnBX9jvLeHWqFDi8FiUlFW4=", "dev": true, "requires": { - "chalk": "1.1.3" + "chalk": "^1.0.0" } }, "superagent": { @@ -6790,16 +6678,16 @@ "integrity": "sha1-cDUpoHFOV+EjlZ3e+84ZOy5Q0RU=", "dev": true, "requires": { - "component-emitter": "1.2.1", - "cookiejar": "2.1.1", - "debug": "2.2.0", - "extend": "3.0.0", + "component-emitter": "^1.2.0", + "cookiejar": "^2.0.6", + "debug": "^2.2.0", + "extend": "^3.0.0", "form-data": "1.0.0-rc4", - "formidable": "1.1.1", - "methods": "1.1.2", - "mime": "1.3.4", - "qs": "6.2.0", - "readable-stream": "2.3.3" + "formidable": "^1.0.17", + "methods": "^1.1.1", + "mime": "^1.3.4", + "qs": "^6.1.0", + "readable-stream": "^2.0.5" }, "dependencies": { "async": { @@ -6814,9 +6702,9 @@ "integrity": "sha1-BaxrwiIntD5EYfSIFhVUaZ1Pi14=", "dev": true, "requires": { - "async": "1.5.2", - "combined-stream": "1.0.5", - "mime-types": "2.1.12" + "async": "^1.5.2", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.10" } } } @@ -6827,8 +6715,8 @@ "integrity": "sha1-oFgIHXiPFRXUcA11Aogea3WeRM0=", "dev": true, "requires": { - "methods": "1.1.2", - "superagent": "2.3.0" + "methods": "1.x", + "superagent": "^2.0.0" } }, "supports-color": { @@ -6843,12 +6731,12 @@ "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", "dev": true, "requires": { - "ajv": "4.11.8", - "ajv-keywords": "1.5.1", - "chalk": "1.1.3", - "lodash": "4.16.4", + "ajv": "^4.7.0", + "ajv-keywords": "^1.0.0", + "chalk": "^1.1.1", + "lodash": "^4.0.0", "slice-ansi": "0.0.4", - "string-width": "2.1.1" + "string-width": "^2.0.0" }, "dependencies": { "ansi-regex": { @@ -6869,8 +6757,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "strip-ansi": { @@ -6879,26 +6767,50 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } } } }, + "tdigest": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz", + "integrity": "sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=", + "requires": { + "bintrees": "1.0.1" + } + }, "term-size": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", "dev": true, "requires": { - "execa": "0.7.0" + "execa": "^0.7.0" } }, + "text-encoding": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", + "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", + "dev": true + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "thriftrw": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/thriftrw/-/thriftrw-3.12.0.tgz", + "integrity": "sha512-4YZvR4DPEI41n4Opwr4jmrLGG4hndxr7387kzRFIIzxHQjarPusH4lGXrugvgb7TtPrfZVTpZCVe44/xUxowEw==", + "requires": { + "bufrw": "^1.3.0", + "error": "7.0.2", + "long": "^2.4.0" + } + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -6916,7 +6828,7 @@ "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", "dev": true, "requires": { - "nopt": "1.0.10" + "nopt": "~1.0.10" }, "dependencies": { "nopt": { @@ -6925,7 +6837,7 @@ "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", "dev": true, "requires": { - "abbrev": "1.0.9" + "abbrev": "1" } } } @@ -6935,9 +6847,14 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", "requires": { - "punycode": "1.4.1" + "punycode": "^1.4.1" } }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "tryit": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", @@ -6962,7 +6879,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "1.1.2" + "prelude-ls": "~1.1.2" } }, "type-detect": { @@ -6977,7 +6894,7 @@ "integrity": "sha1-boO6e8MM0zp7sLf7AHN6IIW/nQg=", "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.12" + "mime-types": "~2.1.11" } }, "typedarray": { @@ -6993,9 +6910,9 @@ "dev": true, "optional": true, "requires": { - "source-map": "0.5.7", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" }, "dependencies": { "source-map": { @@ -7026,7 +6943,7 @@ "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", "dev": true, "requires": { - "crypto-random-string": "1.0.0" + "crypto-random-string": "^1.0.0" } }, "unpipe": { @@ -7046,15 +6963,15 @@ "integrity": "sha1-TognpruRUUCrCTVZ1wFOPruDdFE=", "dev": true, "requires": { - "boxen": "1.2.2", - "chalk": "2.3.0", - "configstore": "3.1.1", - "import-lazy": "2.1.0", - "is-installed-globally": "0.1.0", - "is-npm": "1.0.0", - "latest-version": "3.1.0", - "semver-diff": "2.1.0", - "xdg-basedir": "3.0.0" + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" }, "dependencies": { "ansi-styles": { @@ -7063,7 +6980,7 @@ "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", "dev": true, "requires": { - "color-convert": "1.9.1" + "color-convert": "^1.9.0" } }, "chalk": { @@ -7072,9 +6989,9 @@ "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" + "ansi-styles": "^3.1.0", + "escape-string-regexp": "^1.0.5", + "supports-color": "^4.0.0" } }, "has-flag": { @@ -7089,7 +7006,7 @@ "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { - "has-flag": "2.0.0" + "has-flag": "^2.0.0" } } } @@ -7100,7 +7017,7 @@ "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", "dev": true, "requires": { - "prepend-http": "1.0.4" + "prepend-http": "^1.0.1" } }, "user-home": { @@ -7109,16 +7026,7 @@ "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", "dev": true, "requires": { - "os-homedir": "1.0.2" - } - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dev": true, - "requires": { - "inherits": "2.0.1" + "os-homedir": "^1.0.0" } }, "util-deprecate": { @@ -7150,13 +7058,27 @@ "extsprintf": "1.0.2" } }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "which": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "widest-line": { @@ -7165,7 +7087,7 @@ "integrity": "sha1-DAnIXCqUaD0Nfq+O4JfVZL8OEFw=", "dev": true, "requires": { - "string-width": "1.0.2" + "string-width": "^1.0.1" } }, "window-size": { @@ -7180,13 +7102,13 @@ "resolved": "https://registry.npmjs.org/winston/-/winston-2.2.0.tgz", "integrity": "sha1-LIU92Hq1UqjoSF1yy7+aIobwKbc=", "requires": { - "async": "1.0.0", - "colors": "1.0.3", - "cycle": "1.0.3", - "eyes": "0.1.8", - "isstream": "0.1.2", - "pkginfo": "0.3.1", - "stack-trace": "0.0.9" + "async": "~1.0.0", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "pkginfo": "0.3.x", + "stack-trace": "0.0.x" }, "dependencies": { "async": { @@ -7202,6 +7124,67 @@ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha1-Z+FFz/UQpqaYS98RUpEdadLrnkM=", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U=" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=" + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha1-2v1PlVmnWFz7pSnGoKT3NIjr1MU=", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI=", + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -7213,7 +7196,7 @@ "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "dev": true, "requires": { - "mkdirp": "0.5.1" + "mkdirp": "^0.5.1" } }, "write-file-atomic": { @@ -7222,9 +7205,9 @@ "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "imurmurhash": "0.1.4", - "signal-exit": "3.0.2" + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" } }, "xdg-basedir": { @@ -7233,11 +7216,20 @@ "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", "dev": true }, + "xorshift": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/xorshift/-/xorshift-0.2.1.tgz", + "integrity": "sha1-/NgiZ+k1HBPw+5xzMH8lMx0pxjo=" + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha1-f0k00PfKjFb5UxSTndzS3ZHOHVU=" }, "yallist": { "version": "2.1.2", @@ -7252,11 +7244,16 @@ "dev": true, "optional": true, "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", "window-size": "0.1.0" } + }, + "yargs-parser": { + "version": "20.2.7", + "resolved": "https://artifactory.globoi.com/artifactory/api/npm/npm-repos/yargs-parser/-/yargs-parser-20.2.7.tgz", + "integrity": "sha1-Yd+FwRPt+1p6TjbriqYO9CPLyQo=" } } } diff --git a/package.json b/package.json index fb6aec7..d696abb 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,13 @@ { "name": "@globocom/backstage-functions", - "version": "0.1.0", + "version": "0.4.3", "description": "Remote serverless code executor", "main": "index.js", "scripts": { - "test": "REDIS_KEY_PREFIX=test nyc mocha --recursive test/", + "test": "REDIS_KEY_PREFIX=test nyc mocha --ui bdd --recursive test/", "send_cover": "nyc report --reporter=text-lcov | coveralls", - "start_dev": "nf -j Procfile.local -e .env.local start", + "start_dev": "which nf && nf -j Procfile.local -e .env.local start", + "start_sandbox": "NUM_CPUS=1 STORAGE=inmemory nf -j Procfile.sandbox -e .env.local start", "lint": "eslint lib test" }, "repository": { @@ -20,21 +21,36 @@ "backstage" ], "engines": { - "node": ">=8.9.1" + "node": ">=8.13.0" }, "author": "Backstage Team ", "license": "MIT", "dependencies": { - "@globocom/backstage-functions-sandbox": "^0.3.2", + "@globocom/backstage-functions-sandbox": "^0.5.3", + "@opentelemetry/api": "^0.18.1", + "@opentelemetry/core": "^0.19.0", + "@opentelemetry/exporter-collector-grpc": "^0.19.0", + "@opentelemetry/instrumentation": "^0.19.0", + "@opentelemetry/instrumentation-express": "^0.16.0", + "@opentelemetry/instrumentation-http": "^0.19.0", + "@opentelemetry/instrumentation-ioredis": "^0.16.0", + "@opentelemetry/node": "^0.19.0", + "@opentelemetry/tracing": "^0.19.0", "async": "^2.0.1", "body-parser": "^1.15.2", "deepcopy": "^0.6.3", "express": "^4.14.0", - "gelf-pro": "^1.1.0", + "express-opentracing": "^0.1.1", + "gelf": "^2.0.1", + "google-auth-library": "^9.2.0", "ioredis": "^3.1.4", + "jaeger-client": "^3.18.0", "jsonschema": "^1.1.0", "lodash": "^4.16.2", "morgan": "^1.7.0", + "node-fetch": "^2.6.0", + "opentracing": "^0.14.4", + "prom-client": "^11.5.3", "raven": "^2.2.1", "request": "^2.81.0", "stack-trace": "^0.0.9", @@ -56,7 +72,7 @@ "mocha": "^3.0.2", "nodemon": "^1.10.2", "nyc": "^11.3.0", - "sinon": "^1.17.6", + "sinon": "^4.1.3", "supertest": "^2.0.0" } } diff --git a/test/fakes/FakeStorage.js b/test/fakes/FakeStorage.js index 65a3ac4..34920dd 100644 --- a/test/fakes/FakeStorage.js +++ b/test/fakes/FakeStorage.js @@ -1,6 +1,6 @@ /* eslint class-methods-use-this: ['error', { "exceptMethods": [ 'listNamespaces', 'getCode', 'deleteCode', 'getCodeByCache', 'compileCode', 'runScript', - 'getNamespace', 'deleteNamespace' + 'getNamespace', 'deleteNamespace', 'search' ]}]*/ const Sandbox = require('@globocom/backstage-functions-sandbox'); @@ -24,6 +24,28 @@ class FakeStorage extends Storage { }; } + async search(namespace, id) { + if (id === 'function1' && namespace === 'namespace1') { + return { + items: [ + { namespace: 'namespace1', id: 'function1' }, + ], + }; + } + if (namespace === 'namespace1') { + return { + items: [ + { namespace: 'namespace1', id: 'function1' }, + { namespace: 'namespace1', id: 'function2' }, + ], + }; + } + if (namespace === 'error' || id === 'error') { + throw new Error('Storage error'); + } + return { items: [] }; + } + async getCode(namespace, id) { if (id === 'not-found') { return null; @@ -36,18 +58,6 @@ class FakeStorage extends Storage { }; } - async postCode(namespace, id, code) { - this.lastPutCode = code; - - if (id === 'exists') { - throw new Error('Code already exists'); - } else if (id === 'error') { - throw new Error('Storage error'); - } - - return [1, 1]; - } - async putCode(namespace, id, code) { this.lastPutCode = code; if (id === 'error') { diff --git a/test/integration/domain/http/routers/FunctionsRouter.test.js b/test/integration/domain/http/routers/FunctionsRouter.test.js index 84d1b77..a43ec4d 100644 --- a/test/integration/domain/http/routers/FunctionsRouter.test.js +++ b/test/integration/domain/http/routers/FunctionsRouter.test.js @@ -3,52 +3,6 @@ const expect = require('chai').expect; const routes = require('../../../../../lib/http/routes'); describe('FunctionRouter integration', () => { - describe('POST /functions/:namespace/:id', () => { - describe('when code is correct', () => { - const code = ` - function main(req, res) { - res.send({ foo: 'bar' }); - } - `; - - it('should put the code at the function', (done) => { - request(routes) - .post('/functions/function-router-test/test1') - .send({ code }) - .expect('content-type', /json/) - .expect(200) - .end((err, res) => { - if (err) { - done(err); - } - expect(res.body.code).to.be.eql(code); - expect(res.body.id).to.be.eql('test1'); - done(); - }); - }); - }); - - describe('when code already exists', () => { - const code = ` - function main(req, res) { - res.send({ foo: 'bar' }); - } - `; - - it('should returns 400 - Bad Request', (done) => { - request(routes) - .post('/functions/function-router-test/test1') - .send({ code }) - .expect('content-type', /json/) - .expect(400) - .end((err, res) => { - expect(res.body.error).to.be.eql('The key function-router-test:test1 already exists'); - done(); - }); - }); - }); - }); - describe('PUT /functions/:namespace/:id', () => { describe('when code is correct', () => { const code = ` diff --git a/test/integration/domain/storage/storage-redis.test.js b/test/integration/domain/storage/storage-redis.test.js index 0f12b8e..269b8d4 100644 --- a/test/integration/domain/storage/storage-redis.test.js +++ b/test/integration/domain/storage/storage-redis.test.js @@ -80,6 +80,50 @@ describe('StorageRedis', () => { }); // when code is found is already tested above + + describe('sentryDSN', () => { + beforeEach(async () => { + this.namespace = 'backstage'; + this.code = { + id: 'test', + code: 'a = 1;', + hash: '123', + }; + await storage.deleteNamespace(this.namespace); + await storage.deleteCode(this.namespace, this.code.id); + }); + + it('when is configured in the namespace', async () => { + const x = await storage.putCode(this.namespace, this.code.id, this.code); + expect(x).to.be.eql('OK'); + await storage.putNamespace(this.namespace, { + namespace: this.namespace, + sentryDSN: 'http://my-sentry.io/foo', + }); + + const result = await storage.getCode(this.namespace, this.code.id); + expect(result.sentryDSN).to.be.eql('http://my-sentry.io/foo'); + }); + + it('when is configured in the env', async () => { + this.code.env = { + sentryDSN: 'http://my-sentry.io/fooenv', + }; + const x = await storage.putCode(this.namespace, this.code.id, this.code); + expect(x).to.be.eql('OK'); + + const result = await storage.getCode(this.namespace, this.code.id); + expect(result.sentryDSN).to.be.eql('http://my-sentry.io/fooenv'); + }); + + it('when isn`t configured', async () => { + const x = await storage.putCode(this.namespace, this.code.id, this.code); + expect(x).to.be.eql('OK'); + + const result = await storage.getCode(this.namespace, this.code.id); + expect(result.sentryDSN).to.be.null; + }); + }); }); describe('#delete()', () => { @@ -480,8 +524,8 @@ describe('StorageRedis', () => { before(() => { sandbox = sinon.sandbox.create(); fakeWorker = new FakeWorker(); - sandbox.stub(storage, 'worker', fakeWorker); - sandbox.stub(storage, 'ping', () => new Promise(() => {})); + sandbox.stub(storage, 'worker').value(fakeWorker); + sandbox.stub(storage, 'ping').callsFake(() => new Promise(() => {})); }); after(() => { @@ -497,4 +541,87 @@ describe('StorageRedis', () => { }); }); }); + + + describe('#search()', () => { + describe('with valid values', () => { + before(() => { + storage.setNamespaceMember('namespace1', 'function1'); + storage.setNamespaceMember('namespace1', 'function2'); + storage.setNamespaceMember('namespace2', 'function1'); + for (let i = 1; i <= 25; i += 1) { + storage.setNamespaceMember('namespace3', `function${i}`); + } + }); + + it('with namespace', async () => { + const list = await storage.search('namespace1'); + expect(list).to.deep.equal({ + items: [ + { + id: 'function1', + namespace: 'namespace1', + }, + { + id: 'function2', + namespace: 'namespace1', + }, + ], + nextPage: 2, + page: 1, + perPage: 10, + }); + }); + + it('with namespace and id', async () => { + const list = await storage.search('namespace1', 'function1'); + expect(list).to.deep.equal({ + items: [ + { + id: 'function1', + namespace: 'namespace1', + }, + ], + nextPage: 2, + page: 1, + perPage: 10, + }); + }); + + it('with page 1', async () => { + const list = await storage.search('namespace3'); + expect(list.items).to.have.lengthOf(10); + }); + + it('with page 2', async () => { + const page = 2; + const list = await storage.search('namespace3', '', page); + expect(list.items).to.have.lengthOf(10); + }); + + it('with page 3', async () => { + const page = 3; + const list = await storage.search('namespace3', '', page); + expect(list.items).to.have.lengthOf(5); + }); + + it('with perPage 5', async () => { + const perPage = 5; + const list = await storage.search('namespace3', '', 1, perPage); + expect(list.items).to.have.lengthOf(perPage); + }); + }); + + describe('with invalid values', () => { + it('without namespace and function id', async () => { + const list = await storage.search('invalid-namespace', 'id'); + expect(list).to.deep.equal({ + items: [], + nextPage: 2, + page: 1, + perPage: 10, + }); + }); + }); + }); }); diff --git a/test/unit/domain/ErrorTracker.test.js b/test/unit/domain/ErrorTracker.test.js index 22e61d8..0f427f6 100644 --- a/test/unit/domain/ErrorTracker.test.js +++ b/test/unit/domain/ErrorTracker.test.js @@ -8,6 +8,7 @@ class FakeSentryDSN extends EventEmitter { constructor() { super(); this.nextEventID = '6701c255-9431-46f4-a59e-eda424742dab'; + this.sent = false; } generateEventId() { return this.nextEventID; @@ -18,6 +19,7 @@ class FakeSentryDSN extends EventEmitter { } send(ctx, callback) { + this.sent = true; this.emit('sent', ctx); callback(null); } @@ -26,6 +28,8 @@ class FakeSentryDSN extends EventEmitter { describe('ErrorTracker', () => { describe('#notify', () => { let resultCtx; + let sentryClient; + let errTracker; before((done) => { const err = new Error('testing'); @@ -40,9 +44,9 @@ describe('ErrorTracker', () => { throw new Error('testing'); } `; - const sentryClient = new FakeSentryDSN(); + sentryClient = new FakeSentryDSN(); - const errTracker = new ErrorTracker({ + errTracker = new ErrorTracker({ sentryDSN: 'http://my-sentry/project', filename: 'testing/testing.js', extra: { @@ -102,7 +106,7 @@ describe('ErrorTracker', () => { }); it('should contains the culprit', () => { - expect(resultCtx.culprit).to.be.eql('testing at main'); + expect(resultCtx.culprit).to.be.eql('testing/testing.js: testing at main'); }); it('should contains the event_id', () => { @@ -141,7 +145,21 @@ describe('ErrorTracker', () => { }); it('should contains the message', () => { - expect(resultCtx.message).to.be.eql('Error: testing'); + expect(resultCtx.message).to.be.eql('testing/testing.js: Error: testing'); + }); + + describe('when err contains a non error status code', () => { + before(() => { + sentryClient.sent = false; + + const err = new Error('Not a critical error'); + err.statusCode = 404; + errTracker.notify(err); + }); + + it('should ignore error and not send to sentry', () => { + expect(sentryClient.sent).to.be.false; + }); }); }); }); diff --git a/test/unit/domain/LogStorage.test.js b/test/unit/domain/LogStorage.test.js index 3ce4d63..a9ff230 100644 --- a/test/unit/domain/LogStorage.test.js +++ b/test/unit/domain/LogStorage.test.js @@ -28,7 +28,6 @@ describe('StdoutLogStorage', () => { }); }); - describe('GelfLogStorage', () => { /* eslint no-underscore-dangle: ["error", { "allow": [ "_stdout", "_stderr", "_status", "_request_time", "_group", "_file", @@ -45,17 +44,19 @@ describe('GelfLogStorage', () => { let gelfServer; let sandbox; let logStorage; + let newLogStorage; before(() => { gelfServer = new Graygelf(); gelfServer.listen(); sandbox = sinon.sandbox.create(); - sandbox.stub(config.log, 'fieldsFromHTTPHeaders', { + sandbox.stub(config.log, 'fieldsFromHTTPHeaders').value({ rid: 'x-rid', clientId: 'x-client-id', }); + config.log.hosts = ['localhost', '127.0.0.1']; logStorage = new GelfLogStorage('test-namespace', 'test-id', req); }); @@ -70,12 +71,43 @@ describe('GelfLogStorage', () => { expect(stdout.buf).to.be.an.instanceof(MemoryStream); }); + it('should prefix extra fields with _', () => { + const extra = { a: 1, b: 2, _c: 3 }; + expect(GelfLogStorage.prepareExtraFields(extra)).to.be.eqls({ _a: 1, _b: 2, _c: 3 }); + }); + it('should create prefixed stdout console', () => { const stderr = logStorage.console._stderr; expect(stderr.prefix).to.be.eql('error:'); expect(stderr.buf).to.be.an.instanceof(MemoryStream); }); + describe('when has more than one host in config.log.hosts', () => { + before(() => { + newLogStorage = new GelfLogStorage('test-namespace', 'test-id', req); + }); + + after(() => { + config.log.hosts = 'localhost'; + }); + + it('should be different gelfClients', () => { + const client1 = newLogStorage.gelfClients[0].config.graylogHostname; + const client2 = newLogStorage.gelfClients[1].config.graylogHostname; + + expect(client1 === client2).to.be.false; + expect(newLogStorage.gelfClients[0] === newLogStorage.gelfClients[1]).to.be.false; + }); + + it('should have a gelfClients property in GelfLogStorage', () => { + expect(newLogStorage).to.have.property('gelfClients'); + }); + + it('should initialize more than one gelfClient', () => { + expect(newLogStorage.gelfClients.length).to.be.eql(2); + }); + }); + describe('#flush', () => { let receivedMsg; @@ -178,5 +210,28 @@ describe('GelfLogStorage', () => { expect(receivedMsg.level).to.be.eql(3); }); }); + + describe('when exist a console overflow', () => { + before((done) => { + for (let i = 0; i < 1000; i += 1) { + logStorage.console.info(`line ${i}`); + } + + gelfServer.once('message', (msg) => { + receivedMsg = msg; + done(); + }); + + logStorage.flush({ + status: 500, + requestTime: 20, + }); + }); + + it('should truncate the `full_message` attribute', () => { + expect(receivedMsg.full_message.length).to.be.eql(3010); + expect(receivedMsg.full_message.endsWith('\ntruncated')).to.be.true; + }); + }); }); }); diff --git a/test/unit/domain/Metric.test.js b/test/unit/domain/Metric.test.js index d8bff39..587ea1a 100644 --- a/test/unit/domain/Metric.test.js +++ b/test/unit/domain/Metric.test.js @@ -1,61 +1,37 @@ -const dgram = require('dgram'); const expect = require('chai').expect; -const sinon = require('sinon'); +const prometheusClient = require('prom-client'); -const config = require('../../../lib/support/config'); const Metric = require('../../../lib/domain/Metric'); describe('Metric', () => { - let sandbox; - let onMessage; - - before((done) => { - sandbox = sinon.sandbox.create(); - sandbox.stub(config.metric, 'client', 'functions-test'); - sandbox.stub(config.metric, 'udpHost', 'localhost'); - - - const server = dgram.createSocket('udp4'); - - server.on('error', (err) => { - done(err); - server.close(); + describe('#observeFunctionRun', () => { + beforeEach(() => { + prometheusClient.register.resetMetrics(); }); - server.on('message', (msg) => { - onMessage(msg); - }); + it('should increment metrics in registry', () => { + new Metric().observeFunctionRun({ namespace: 'xpto', id: 'blah', status: 403 }); + const data = prometheusClient.register.metrics(); + expect(data).to.be.include('backstage_functions_function_run_total{namespace="xpto",id="blah",status="4xx"} 1'); + expect(data).to.be.include('backstage_functions_function_run_duration_seconds_bucket{le="0.05",namespace="xpto",id="blah"} 1'); - server.on('listening', () => { - sandbox.stub(config.metric, 'udpPort', server.address().port); - done(); + expect(data).to.be.include('backstage_functions_overview_run_total{status="4xx"} 1'); + expect(data).to.be.include('backstage_functions_overview_run_duration_seconds_bucket{le="0.05"} 1'); }); - - server.bind(0); }); - after(() => { - sandbox.restore(); - }); + describe('#observePipelineRun', () => { + beforeEach(() => { + prometheusClient.register.resetMetrics(); + }); - it('should send metric by udp', (done) => { - let spent; - const metric = new Metric('test-metric'); - setTimeout(() => { - spent = metric.finish({ - test: 'testing', - }); - }, 100); - - onMessage = (msg) => { - const data = JSON.parse(msg); - expect(data.client).to.be.eql('functions-test'); - expect(data.metric).to.be.eql('test-metric'); - expect(data.time).to.be.below(120); // time in milleseconds - expect(spent).to.be.below(1); // time in seconds - expect(data.test).to.be.eql('testing'); - done(); - }; + it('should increment metrics in registry', () => { + new Metric().observePipelineRun(403); + const data = prometheusClient.register.metrics(); + + expect(data).to.be.include('backstage_functions_pipeline_run_total{status="4xx"} 1'); + expect(data).to.be.include('backstage_functions_pipeline_run_duration_seconds_bucket{le="0.05"} 1'); + }); }); }); diff --git a/test/unit/domain/Pipeline.test.js b/test/unit/domain/Pipeline.test.js index f339c24..35efe8c 100644 --- a/test/unit/domain/Pipeline.test.js +++ b/test/unit/domain/Pipeline.test.js @@ -1,4 +1,5 @@ const expect = require('chai').expect; +const opentracing = require('opentracing'); const Pipeline = require('../../../lib/domain/Pipeline'); @@ -16,6 +17,8 @@ describe('Pipeline', () => { let step200b; let step404; let stepCrash; + let tracer; + let span; beforeEach(() => { req = { @@ -82,75 +85,99 @@ describe('Pipeline', () => { } `), }; + tracer = new opentracing.MockTracer(); + span = tracer.startSpan('test span'); }); it('should be able to run unique function', async () => { - const result = await new Pipeline(sandbox, req, [step200]).run(); + const result = await new Pipeline(sandbox, req, [step200], span).run(); expect(result.body.ok).to.be.eql(true); expect(result.status).to.be.eql(200); }); it('should be able to run unique function with 304', async () => { - const result = await new Pipeline(sandbox, req, [step304]).run(); + const result = await new Pipeline(sandbox, req, [step304], span).run(); expect(result.status).to.be.eql(304); expect(result.body).to.be.eql(null); }); it('should be able to run two functions', async () => { - const result = await new Pipeline(sandbox, req, [step200, step200b]).run(); + const result = await new Pipeline(sandbox, req, [step200, step200b], span).run(); expect(result.body.ok).to.be.eql(true); expect(result.body.ok2).to.be.eql(true); expect(result.status).to.be.eql(200); }); it('should be able to run three functions', async () => { - const result = await new Pipeline(sandbox, req, [step200, step200b, step200env]).run(); + const result = await new Pipeline(sandbox, req, [step200, step200b, step200env], span).run(); expect(result.body.ok).to.be.eql(true); expect(result.body.ok2).to.be.eql(true); expect(result.body.env.STEP_VAR).to.be.eql('foo'); expect(result.status).to.be.eql(200); + + const mockSpanReport = tracer.report(); + const spans = mockSpanReport.spans.filter(s => s.operationName() === 'run function'); + expect(spans.length).to.be.eql(3); + expect(spans[0].durationMs()).to.be.gte(0); }); it('should be able to run two functions, one with 304', async () => { - const result = await new Pipeline(sandbox, req, [step200, step304]).run(); + const result = await new Pipeline(sandbox, req, [step200, step304], span).run(); expect(result.body.ok).to.be.eql(true); expect(result.status).to.be.eql(200); }); it('should be able to run three functions, two with 304', async () => { - const result = await new Pipeline(sandbox, req, [step200, step304, step304]).run(); + const result = await new Pipeline(sandbox, req, [step200, step304, step304], span).run(); expect(result.body.ok).to.be.eql(true); expect(result.status).to.be.eql(200); }); it('should be able to run three functions, one with 304', async () => { - const result = await new Pipeline(sandbox, req, [step200, step304, step200b]).run(); + const result = await new Pipeline(sandbox, req, [step200, step304, step200b], span).run(); expect(result.body.ok).to.be.eql(true); expect(result.body.ok2).to.be.eql(true); expect(result.status).to.be.eql(200); }); it('should be able to run one function with 404', async () => { - const result = await new Pipeline(sandbox, req, [step404]).run(); - expect(result.body.error).to.be.eql('Not found an item'); - expect(result.status).to.be.eql(404); + try { + await new Pipeline(sandbox, req, [step404], span).run(); + } catch (err) { + expect(err.message).to.be.eql('Not found an item'); + expect(err.statusCode).to.be.eql(404); + return; + } + + throw new Error('Not raised an error'); }); it('should be able to run three functions with 404', async () => { - const result = await new Pipeline(sandbox, req, [step200, step404, step200b]).run(); - expect(result.body.error).to.be.eql('Not found an item'); - expect(result.body.namespace).to.be.eql('backstage'); - expect(result.body.functionId).to.be.eql('step404'); - expect(result.status).to.be.eql(404); + try { + await new Pipeline(sandbox, req, [step200, step404, step200b], span).run(); + } catch (err) { + expect(err.message).to.be.eql('Not found an item'); + expect(err.statusCode).to.be.eql(404); + return; + } + + throw new Error('Not raised an error'); }); it('should fail if the first function fail', async () => { try { - await new Pipeline(sandbox, req, [step200, stepCrash]).run(); + await new Pipeline(sandbox, req, [step200, stepCrash], span).run(); throw new Error('Not failed'); } catch (err) { expect(err.message).to.be.eql('res.undefinedMethod is not a function'); } + + const mockSpanReport = tracer.report(); + const spans = mockSpanReport.spans.filter(s => s.operationName() === 'run function'); + expect(spans.length).to.be.eql(2); + expect(spans[0].durationMs()).to.be.gte(0); + expect(spans[0].tags()).to.be.eql({}); + expect(spans[1].tags()).to.be.eql({ error: true }); }); }); }); diff --git a/test/unit/domain/status.test.js b/test/unit/domain/status.test.js index 6e76300..77f4b9a 100644 --- a/test/unit/domain/status.test.js +++ b/test/unit/domain/status.test.js @@ -1,5 +1,7 @@ const expect = require('chai').expect; +const sinon = require('sinon'); const Status = require('../../../lib/domain/status'); +const ErrorTracker = require('../../../lib/domain/ErrorTracker'); const NotWorkingStorage = require('../../fakes/NotWorkingStorage'); const WorkingStorage = require('../../fakes/WorkingStorage'); @@ -8,26 +10,63 @@ describe('Status', () => { const status1 = new Status(new WorkingStorage()); const status2 = new Status(new NotWorkingStorage()); const properties = ['name', 'status', 'message', 'time']; + let sinonSandbox; + + beforeEach(() => { + sinonSandbox = sinon.sandbox.create(); + }); + + afterEach(() => { + sinonSandbox.restore(); + }); it('should contain mandatory properties on response', async () => { - const output1 = await status1.run(); - const output2 = await status2.run(); + sinonSandbox.stub(ErrorTracker, 'ping').resolves('Mocked'); + const services1 = await status1.run(); + const services2 = await status2.run(); - expect(output1).to.include.keys(properties); - expect(output2).to.include.keys(properties); + expect(services1[0]).to.include.keys(properties); + expect(services2[0]).to.include.keys(properties); + + expect(services1[1]).to.include.keys(properties); + expect(services2[1]).to.include.keys(properties); }); - describe('when service is up', () => { + describe('when storage service is up', () => { it('should show WORKING status', async () => { - const output = await status1.run(); - expect(output.status).to.eq('WORKING'); + sinonSandbox.stub(ErrorTracker, 'ping').resolves('Mocked'); + const services = await status1.run(); + expect(services[0].status).to.eq('WORKING'); }); }); - describe('when service is down', () => { + describe('when storage service is down', () => { it('should show FAILED status', async () => { - const output = await status2.run(); - expect(output.status).to.eq('FAILED'); + sinonSandbox.stub(ErrorTracker, 'ping').resolves('Mocked'); + const services = await status2.run(); + expect(services[0].status).to.eq('FAILED'); + }); + }); + + describe('when error tracker is up', () => { + it('should show WORKING status', async () => { + sinonSandbox.stub(ErrorTracker, 'ping').resolves('Mocked'); + const services = await status1.run(); + + expect(services[1].name).to.be.eql('Sentry'); + expect(services[1].status).to.be.eql('WORKING'); + expect(services[1].message).to.be.eql('Mocked'); + }); + }); + + describe('when error tracker is down', () => { + it('should show FAILED status', async () => { + sinonSandbox.stub(ErrorTracker, 'ping').rejects(new Error('Foo')); + const services = await status2.run(); + + expect(services[1].name).to.be.eql('Sentry'); + expect(services[1].status).to.be.eql('FAILED'); + expect(services[1].message).to.be.eql('Error: Foo'); }); }); }); diff --git a/test/unit/domain/storage.test.js b/test/unit/domain/storage.test.js index 9dca214..1aa2737 100644 --- a/test/unit/domain/storage.test.js +++ b/test/unit/domain/storage.test.js @@ -11,13 +11,6 @@ describe('storage', () => { }); }); - describe('#postCode', () => { - it('should throws an unimplemented error', () => { - const fn = () => storage.postCode(); - expect(fn).to.throw(Error, /unimplemented method for Storage interface/); - }); - }); - describe('#putCode', () => { it('should throws an unimplemented error', () => { const fn = () => storage.putCode(); @@ -45,4 +38,42 @@ describe('storage', () => { expect(fn).to.throw(Error, /unimplemented method for Storage interface/); }); }); + + describe('#search', () => { + it('should throws an unimplemented error', () => { + const fn = () => storage.search(); + expect(fn).to.throw(Error, /unimplemented method for Storage interface/); + }); + }); + + describe('#getSentryByEnvOrNamespace', () => { + it('should return sentryDSN from env', async () => { + const code = { + env: { + sentryDSN: 'http://my-sentry.io/fooenv', + }, + namespaceSettings: { + sentryDSN: 'http://my-sentry.io/foo', + }, + }; + const sentry = await Storage.getSentryByEnvOrNamespace(code); + expect(sentry).to.be.eql('http://my-sentry.io/fooenv'); + }); + + it('should return sentryDSN from namespace', async () => { + const code = { + namespaceSettings: { + sentryDSN: 'http://my-sentry.io/foo', + }, + }; + + const sentry = await Storage.getSentryByEnvOrNamespace(code); + expect(sentry).to.be.eql('http://my-sentry.io/foo'); + }); + + it('should return null when sentryDSN isn`t configured', async () => { + const sentry = await Storage.getSentryByEnvOrNamespace({}); + expect(sentry).to.be.null; + }); + }); }); diff --git a/test/unit/domain/storageInMemory.test.js b/test/unit/domain/storageInMemory.test.js new file mode 100644 index 0000000..274b92f --- /dev/null +++ b/test/unit/domain/storageInMemory.test.js @@ -0,0 +1,503 @@ +const expect = require('chai').expect; +const uuidV4 = require('uuid/v4'); +const StorageInMemory = require('../../../lib/domain/storage/InMemory'); + +const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/; + + +describe('StorageInMemory', () => { + let storage; + + beforeEach(() => { + storage = new StorageInMemory(); + }); + + describe('#putCode() and #getCode()', () => { + it('should write a hash for the code', async () => { + const code = { + id: 'test', + code: 'a = 1;', + hash: '123', + env: { + CLIENT_ID: 'my client id', + MY_VAR: 'my var', + }, + }; + const x = await storage.putCode('backstage', 'test', code); + expect(x).to.be.eql('OK'); + + const code2 = await storage.getCode('backstage', 'test'); + + expect(code2.id).to.be.eql('test'); + expect(code2.namespace).to.be.eql('backstage'); + expect(code2.code).to.be.eql('a = 1;'); + expect(code2.hash).to.be.eql('123'); + expect(code2.versionID).to.match(UUID_REGEX); + expect(code2.env.CLIENT_ID).to.be.eql('my client id'); + expect(code2.env.MY_VAR).to.be.eql('my var'); + }); + + it('should have a created equal updated for new function', async () => { + const code = { + id: uuidV4(), + code: 'a = 2;', + hash: '123', + }; + + const x = await storage.putCode('backstage', code.id, code); + expect(x).to.be.eql('OK'); + + const code2 = await storage.getCode('backstage', code.id); + expect(code2.created).to.be.eql(code2.updated); + }); + }); + + + describe('#getCode()', () => { + describe('when code id is not found', () => { + it('should yield a null', async () => { + const code = await storage.getCode('backstage', 'not-found'); + expect(code).to.be.null; + }); + }); + + // when code is found is already tested above + }); + + describe('sentryDSN', () => { + beforeEach(async () => { + this.namespace = 'backstage'; + this.code = { + id: 'test', + code: 'a = 1;', + hash: '123', + }; + await storage.deleteNamespace(this.namespace); + await storage.deleteCode(this.namespace, this.code.id); + }); + + it('when is configured in the namespace', async () => { + const x = await storage.putCode(this.namespace, this.code.id, this.code); + expect(x).to.be.eql('OK'); + await storage.putNamespace(this.namespace, { + namespace: this.namespace, + sentryDSN: 'http://my-sentry.io/foo', + }); + + const result = await storage.getCode(this.namespace, this.code.id); + expect(result.sentryDSN).to.be.eql('http://my-sentry.io/foo'); + }); + + it('when is configured in the env', async () => { + this.code.env = { + sentryDSN: 'http://my-sentry.io/fooenv', + }; + const x = await storage.putCode(this.namespace, this.code.id, this.code); + expect(x).to.be.eql('OK'); + + const result = await storage.getCode(this.namespace, this.code.id); + expect(result.sentryDSN).to.be.eql('http://my-sentry.io/fooenv'); + }); + + it('when isn`t configured', async () => { + const x = await storage.putCode(this.namespace, this.code.id, this.code); + expect(x).to.be.eql('OK'); + + const result = await storage.getCode(this.namespace, this.code.id); + expect(result.sentryDSN).to.be.null; + }); + }); + + describe('#delete()', () => { + it('should write a hash for the code', async () => { + const id = 'test'; + const namespace = 'backstage'; + const code = { + id, + code: 'a = 1;', + hash: '123', + }; + const putResponse = await storage.putCode(namespace, id, code); + expect(putResponse).to.be.eql('OK'); + + const deleteResponse = await storage.deleteCode(namespace, id); + expect(deleteResponse).to.be.eql(1); + + const code2 = await storage.getCode(namespace, id); + expect(code2).to.be.null; + }); + }); + + describe('#getCodeByCache', () => { + describe('when code is not found in storage', () => { + it('should populate item by preCache', async () => { + const preCache = code => code; + const namespace = 'backstage'; + const id = 'cache-000'; + const cacheResponse = await storage.getCodeByCache(namespace, id, { preCache }); + expect(cacheResponse).to.be.null; + }); + }); + + describe('when code is not found in cache', () => { + it('should populate item by preCache', async () => { + const preCache = (code) => { + code.preCached = true; + preCache.called = true; + return code; + }; + + const namespace = 'backstage'; + const id = 'cache-01'; + const code = { + id, + code: 'b = 1;', + hash: '123', + }; + + const putResponse = await storage.putCode(namespace, id, code); + expect(putResponse).to.be.eql('OK'); + + const cacheResponse = await storage.getCodeByCache(namespace, id, { preCache }); + + expect(cacheResponse.preCached).to.be.true; + expect(preCache.called).to.be.true; + }); + }); + + describe('when code is found in cache and is changed', () => { + it('should repopulate changed item', async () => { + const preCache = (code) => { + code.preCachedByHash = code.hash; + preCache.called = true; + return code; + }; + + const namespace = 'backstage'; + const id = 'cache-03'; + const code = { + id, + code: 'c = 1;', + hash: '123a', + }; + + const putResponse = await storage.putCode(namespace, id, code); + + expect(putResponse).to.be.eql('OK'); + // populate the cache + let cacheResponse = await storage.getCodeByCache(namespace, id, { preCache }); + expect(cacheResponse.preCachedByHash).to.be.eql('123a'); + + // change item in database + code.code = 'd = 2;'; + code.hash = '123b'; + const lastVersionID = cacheResponse.versionID; + await storage.putCode(namespace, id, code); + preCache.called = false; + + cacheResponse = await storage.getCodeByCache(namespace, id, { preCache }); + + expect(cacheResponse.id).to.be.eql(id); + expect(cacheResponse.code).to.be.eql('d = 2;'); + expect(cacheResponse.preCachedByHash).to.be.eql('123b'); + expect(cacheResponse.hash).to.be.eql('123b'); + expect(cacheResponse.versionID).to.match(UUID_REGEX); + expect(cacheResponse.versionID).to.be.not.eql(lastVersionID); + expect(preCache.called).to.be.true; + }); + }); + }); + + describe('getCodesByCache', () => { + const preCache = (code) => { + code.preCached = true; + code.preCachedByVersionID = code.versionID; + return code; + }; + + let code1; + let code2; + + beforeEach(() => { + code1 = { + namespace: 'backstage', + id: 'code1', + code: 'c = 1;', + hash: '123a', + }; + + code2 = { + namespace: 'backstage', + id: 'code2', + code: 'c = 1;', + hash: '123b', + }; + }); + + describe('when all codes are not found', () => { + it('should return null for each code', async () => { + code1.id = 'not-found1'; + code2.id = 'not-found2'; + + const result = await storage.getCodesByCache([code1, code2], { preCache }); + expect(result).to.be.eql([null, null]); + }); + }); + + describe('when all codes are found', () => { + it('should return all codes', async () => { + const [putResponse1, putResponse2] = await Promise.all([ + storage.putCode(code1.namespace, code1.id, code1), + storage.putCode(code2.namespace, code2.id, code2), + ]); + + expect(putResponse1).to.be.eql('OK'); + expect(putResponse2).to.be.eql('OK'); + + const [result1, result2] = await storage.getCodesByCache([code1, code2], { preCache }); + expect(result1.preCached).to.be.true; + expect(result2.preCached).to.be.true; + }); + }); + + describe('when some code are updated', () => { + it('should return all codes', async () => { + const [putResponse1, putResponse2] = await Promise.all([ + storage.putCode(code1.namespace, code1.id, code1), + storage.putCode(code2.namespace, code2.id, code2), + ]); + + expect(putResponse1).to.be.eql('OK'); + expect(putResponse2).to.be.eql('OK'); + + const [savedCode1, savedCode2] = await Promise.all([ + storage.getCode(code1.namespace, code1.id), + storage.getCode(code2.namespace, code2.id), + ]); + + const code1VersionID = savedCode1.versionID; + const code2VersionID = savedCode2.versionID; + + let [result1, result2] = await storage + .getCodesByCache([code1, code2], { preCache }); + + expect(result1.preCached).to.be.true; + expect(result2.preCached).to.be.true; + code2.code = 'console.info("changed");'; + + const putResponse = await storage.putCode(code2.namespace, code2.id, code2); + expect(putResponse).to.be.eql('OK'); + + [result1, result2] = await storage.getCodesByCache([code1, code2], { preCache }); + expect(result1.preCachedByVersionID).to.be.eql(code1VersionID); + expect(result2.preCachedByVersionID).to.be.not.eql(code2VersionID); + }); + }); + }); + + describe('#putCodeEnviromentVariable', () => { + describe('when target function is found', () => { + it('should set enviroment variable', async () => { + const varName = 'MY_SKIP'; + const code = { + namespace: 'backstage', + id: 'test-env', + code: 'a = 1;', + hash: '123', + }; + const x = await storage.putCode(code.namespace, code.id, code); + expect(x).to.be.eql('OK'); + + await storage.putCodeEnviromentVariable(code.namespace, code.id, varName, 'true'); + + const { env, code: source } = await storage.getCode(code.namespace, code.id); + expect(source).to.be.eql(code.code); + expect(env).to.be.eql({ + MY_SKIP: 'true', + }); + }); + }); + + describe('when target function is not found', () => { + it('should raise an error', async () => { + try { + await storage.putCodeEnviromentVariable('backstage', 'test-env-not-found', 'MY_SKIP', 'true'); + } catch (err) { + expect(err.message).to.be.eql('Function not found'); + expect(err.statusCode).to.be.eql(404); + return; + } + + throw new Error('Not raised an expection'); + }); + }); + }); + + describe('#deleteCodeEnviromentVariable', () => { + describe('when target function and target enviroment var is found', () => { + it('should unset enviroment variable', async () => { + const varName = 'TO_BE_DELETE'; + const code = { + namespace: 'backstage', + id: 'test-env-unset', + code: 'a = 1;', + hash: '123', + env: {}, + }; + code.env[varName] = 'me'; + + const x = await storage.putCode(code.namespace, code.id, code); + expect(x).to.be.eql('OK'); + + await storage.deleteCodeEnviromentVariable(code.namespace, code.id, varName); + + const { env, code: source } = await storage.getCode(code.namespace, code.id); + expect(source).to.be.eql(code.code); + expect(env).to.be.eql({}); + }); + }); + + describe('when target enviroment var is not found', () => { + it('should unset enviroment variable', async () => { + const varName = 'TO_BE_DELETE'; + const code = { + namespace: 'backstage', + id: 'test-env-unset', + code: 'a = 1;', + hash: '123', + env: { + TO_MAINTAIN: 'true', + }, + }; + + try { + const x = await storage.putCode(code.namespace, code.id, code); + expect(x).to.be.eql('OK'); + await storage.deleteCodeEnviromentVariable(code.namespace, code.id, varName); + throw new Error('Not raised an expection'); + } catch (err) { + expect(err.message).to.be.eql('Env variable not found'); + expect(err.statusCode).to.be.eql(404); + } + + const { env, code: source } = await storage.getCode(code.namespace, code.id); + expect(source).to.be.eql(code.code); + expect(env).to.be.eql({ + TO_MAINTAIN: 'true', + }); + }); + }); + + describe('when function is not found', () => { + it('should unset enviroment variable', async () => { + const varName = 'TO_BE_DELETE'; + const code = { + namespace: 'backstage', + id: 'test-env-not-found', + }; + + try { + await storage.deleteCodeEnviromentVariable(code.namespace, code.id, varName); + } catch (err) { + expect(err.message).to.be.eql('Function not found'); + expect(err.statusCode).to.be.eql(404); + return; + } + + throw new Error('Not raised an expection'); + }); + }); + }); + + describe('#getNamespace', () => { + describe('when namespace it is not exist', () => { + it('should return null', async () => { + const result = await storage.getNamespace('not-found'); + expect(result).to.be.null; + }); + }); + + describe('when namespace exists', () => { + it('should return related namespace', async () => { + await storage.putNamespace('will-found', { + namespace: 'will-found', + sentryDSN: 'http://my-sentry.io/foo', + }); + + const { namespace, sentryDSN } = await storage.getNamespace('will-found'); + expect(sentryDSN).to.be.eql('http://my-sentry.io/foo'); + expect(namespace).to.be.eql('will-found'); + }); + }); + }); + + describe('#deleteNamespace', () => { + it('should remove namespace', async () => { + await storage.putNamespace('will-delete', { + namespace: 'will-delete', + sentryDSN: 'http://my-sentry.io/foo', + }); + + const { namespace } = await storage.getNamespace('will-delete'); + expect(namespace).to.be.eql('will-delete'); + + await storage.deleteNamespace(namespace); + + const result = await storage.getNamespace('will-delete'); + expect(result).to.be.null; + }); + }); + + describe('#search', () => { + describe('with valid values', () => { + beforeEach(() => { + storage.setNamespaceMember('namespace1', 'function1'); + storage.setNamespaceMember('namespace1', 'function2'); + storage.setNamespaceMember('namespace2', 'function1'); + }); + + it('with namespace', async () => { + const list = await storage.search('namespace1'); + expect(list).to.deep.equal({ + items: [ + { + id: 'function1', + namespace: 'namespace1', + }, + { + id: 'function2', + namespace: 'namespace1', + }, + ], + page: 1, + perPage: 10, + }); + }); + + it('with namespace and id', async () => { + const list = await storage.search('namespace1', 'function1'); + expect(list).to.deep.equal({ + items: [ + { + id: 'function1', + namespace: 'namespace1', + }, + ], + page: 1, + perPage: 10, + }); + }); + }); + + describe('with invalid values', () => { + it('without namespace and function id', async () => { + const list = await storage.search('invalid-namespace', 'id'); + expect(list).to.deep.equal({ + items: [], + page: 1, + perPage: 10, + }); + }); + }); + }); +}); diff --git a/test/unit/http/routers/FunctionsRouter.test.js b/test/unit/http/routers/FunctionsRouter.test.js index 91a1dbd..a7b4335 100644 --- a/test/unit/http/routers/FunctionsRouter.test.js +++ b/test/unit/http/routers/FunctionsRouter.test.js @@ -28,130 +28,36 @@ describe('GET /functions', () => { }) .expect(200, done); }); -}); - -describe('POST /functions/:namespace/:id', () => { - before(() => { - routes.set('memoryStorage', new FakeStorage()); - }); - - describe('when code is correct and does not exists', () => { - it('should return the code', (done) => { - const code = 'function main() {}'; - - request(routes) - .post('/functions/backstage/correct') - .send({ code }) - .expect('Content-Type', /json/) - .expect((res) => { - expect(res.profile).to.endsWith('/_schemas/functions/item'); - }) - .expect(() => { - const memoryStorage = routes.get('memoryStorage'); - expect(memoryStorage.lastPutCode).to.be.eql({ - id: 'correct', - hash: 'c177063dc3780c2fe9b4fdc913650e8147c9b8b0', - code, - }); - }) - .expect(200, { - id: 'correct', - code: 'function main() {}', - hash: 'c177063dc3780c2fe9b4fdc913650e8147c9b8b0', - }, done); - }); - }); - - describe('when code is correct and exists', () => { - it('should returns an error', (done) => { - const code = 'function main() {}'; - - request(routes) - .post('/functions/backstage/exists') - .send({ code }) - .expect('Content-Type', /json/) - .expect(500, { - error: 'Code already exists', - }, done); - }); - }); - - describe('when return any error from storage', () => { - it('should return the code', (done) => { - const code = 'function main() {}'; - - request(routes) - .post('/functions/backstage/error') - .send({ code }) - .expect('Content-Type', /json/) - .expect(500, { - error: 'Storage error', - }, done); - }); - }); - - describe('when code has a syntax error', () => { - it('should return a error', (done) => { - request(routes) - .post('/functions/backstage/invalid') - .send({ code: '{)' }) - .expect('Content-Type', /application\/json/) - .expect(400, { - error: 'SyntaxError: Unexpected token )', - stack: '', - }, done); - }); - }); - - describe('when code has a logic error', () => { - it('should return a error', (done) => { - const code = `let a = {}; - function c() { - a.b(); - }; - c()`; - request(routes) - .post('/functions/codes/crazy') - .send({ code }) - .expect('Content-Type', /json/) - .expect(400, { - error: 'TypeError: a.b is not a function', - stack: 'at c (codes/crazy.js:3)\nat codes/crazy.js:5\nat codes/crazy.js:6', - }, done); - }); + it('search by namespace', (done) => { + request(routes) + .get('/functions?namespace=namespace1') + .expect('Content-Type', /json/) + .expect(200, { + items: [ + { namespace: 'namespace1', id: 'function1' }, + { namespace: 'namespace1', id: 'function2' }, + ], + }, done); }); - describe('when code has a timeout error', () => { - it('should return a error', (done) => { - const code = 'while(1) {};'; - - request(routes) - .post('/functions/codes/timeout') - .send({ code }) - .expect('Content-Type', /json/) - .expect(400, { - error: 'Error: Script execution timed out.', - stack: '', - }, done); - }); + it('search by namespace and function id', (done) => { + request(routes) + .get('/functions?namespace=namespace1&id=function1') + .expect('Content-Type', /json/) + .expect(200, { + items: [ + { namespace: 'namespace1', id: 'function1' }, + ], + }, done); }); - describe('when code is not a string', () => { - it('should return a error', (done) => { - const code = { wrong: 'yes' }; - - request(routes) - .post('/functions/codes/invalid') - .send({ code }) - .expect('Content-Type', /^application\/json/) - .expect(400, { - error: 'Invalid instance', - details: [ - 'instance.code is not of a type(s) string', - ], - }, done); - }); + it('should fail the request with 500 error', (done) => { + request(routes) + .get('/functions?namespace=error') + .expect(500, { + error: 'Storage error', + }, done); }); }); @@ -204,10 +110,11 @@ describe('PUT /functions/:namespace/:id', () => { .put('/functions/backstage/invalid') .send({ code: '{)' }) .expect('Content-Type', /application\/json/) - .expect(400, { - error: 'SyntaxError: Unexpected token )', - stack: '', - }, done); + .expect((res) => { + expect(res.body.error).to.deep.include('Unexpected token'); + expect(res.body.stack).to.be.equal(''); + }) + .expect(400, done); }); }); @@ -238,10 +145,10 @@ describe('PUT /functions/:namespace/:id', () => { .put('/functions/codes/timeout') .send({ code }) .expect('Content-Type', /json/) - .expect(400, { - error: 'Error: Script execution timed out.', - stack: '', - }, done); + .expect((res) => { + expect(res.body.error).to.include('Error: Script execution timed out'); + }) + .expect(400, done); }); }); @@ -456,6 +363,40 @@ describe('PUT /functions/:namespace/:id/env/:env', () => { }); }); + describe('when define secret env variable', () => { + it('should create an enviroment variable', (done) => { + request(routes) + .put('/functions/backstage/correct/env/CLIENT_SECRET') + .set('content-type', 'application/json') + .send('"FOOBAR"') + .expect(() => { + const memoryStorage = routes.get('memoryStorage'); + expect(memoryStorage.lastEnvSet).to.be.eql({ + namespace: 'backstage', + id: 'correct', + env: 'CLIENT_SECRET', + value: 'FOOBAR', + }); + }) + .expect(204, done); + }); + }); + + describe('when get called, not return secret variable', () => { + it('should create an enviroment variable', (done) => { + request(routes) + .get('/functions/backstage/correct') + .set('content-type', 'application/json') + .send() + .expect((res) => { + expect(res.body.env).to.be.eql({ + MY_VAR: 'MY VALUE', + }); + }) + .expect(200, done); + }); + }); + describe('when the target function it\'s not exist', () => { it('should fail the request with 404 error', (done) => { request(routes) @@ -515,3 +456,4 @@ describe('DELETE /functions/:namespace/:id/env/:env', () => { }); }); }); + diff --git a/test/unit/http/routers/MetricsRouter.test.js b/test/unit/http/routers/MetricsRouter.test.js new file mode 100644 index 0000000..03666fd --- /dev/null +++ b/test/unit/http/routers/MetricsRouter.test.js @@ -0,0 +1,39 @@ +const request = require('supertest'); +const express = require('express'); +const sinon = require('sinon'); + +const prometheusClient = require('prom-client'); + +const expect = require('chai').expect; +const MetricsRouter = require('../../../../lib/http/routers/MetricsRouter'); + +describe('GET /metrics', () => { + let sandbox; + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + sandbox.stub(prometheusClient.AggregatorRegistry.prototype, 'clusterMetrics').yields(null, 'my_metric_total 1'); + }); + + afterEach(() => { + sandbox.restore(); + }); + + it('should returns OK text string', (done) => { + const app = express(); + app.use('/metrics', MetricsRouter); + + request(app) + .get('/metrics') + .expect((res) => { + expect(res.text).to.be.eql('my_metric_total 1'); + }) + .end((err) => { + if (err) { + done(err); + } else { + done(); + } + }); + }); +}); diff --git a/test/unit/http/routers/SchemaRouter.test.js b/test/unit/http/routers/SchemaRouter.test.js index 5a4952f..bddd563 100644 --- a/test/unit/http/routers/SchemaRouter.test.js +++ b/test/unit/http/routers/SchemaRouter.test.js @@ -92,6 +92,18 @@ describe('GET /_schema/:schema', () => { method: 'DELETE', rel: 'env-unset', }, + { + href: `http://${host}/namespaces/{namespace}`, + rel: 'namespace', + }, + { + href: `http://${host}/namespaces/{namespace}`, + method: 'PUT', + rel: 'update-namespace', + schema: { + type: 'object', + }, + }, { href: `http://${host}/functions/{namespace}/{id}`, method: 'POST', @@ -179,6 +191,18 @@ describe('GET /_schema/:schema', () => { method: 'DELETE', rel: 'env-unset', }, + { + href: `http://${host}/namespaces/{namespace}`, + rel: 'namespace', + }, + { + href: `http://${host}/namespaces/{namespace}`, + method: 'PUT', + rel: 'update-namespace', + schema: { + type: 'object', + }, + }, ]); }) .expect(200, done);