From 214618df6b1c8c21897fc361efaf4c778ed4d26f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Wed, 10 Jul 2019 15:09:36 +0200 Subject: [PATCH 01/63] wip: APM --- packages/hub/src/hub.ts | 48 ++++++ packages/hub/src/scope.ts | 10 -- packages/hub/src/span.ts | 163 ++++++++++++++---- packages/hub/test/span.test.ts | 6 +- packages/integrations/src/tracing.ts | 2 +- packages/node/src/handlers.ts | 13 +- .../node/test/manual/apm-transaction/main.js | 112 ++++++++++++ packages/types/src/event.ts | 5 +- packages/types/src/index.ts | 2 +- packages/types/src/scope.ts | 5 - packages/types/src/span.ts | 13 ++ 11 files changed, 318 insertions(+), 61 deletions(-) create mode 100644 packages/node/test/manual/apm-transaction/main.js diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index 4cfd2c33872b..4d21047c9166 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -8,12 +8,14 @@ import { Integration, IntegrationClass, Severity, + SpanDetails, User, } from '@sentry/types'; import { consoleSandbox, dynamicRequire, getGlobalObject, isNodeEnv, logger, uuid4 } from '@sentry/utils'; import { Carrier, Layer } from './interfaces'; import { Scope } from './scope'; +import { Span } from './span'; declare module 'domain' { export let active: Domain; @@ -383,6 +385,52 @@ export class Hub implements HubInterface { } return {}; } + + /** + * @inheritDoc + */ + public startSpan(spanDetails?: SpanDetails): Span { + const scope = this.getScope(); + + if (scope) { + const span = scope.getSpan(); + if (span) { + return span.newSpan(spanDetails); + } + } + + return new Span(spanDetails); + } + + /** + * @inheritDoc + */ + public finishSpan(span: Span): string | undefined { + if (!span.timestamp) { + span.finish(); + } + + if (!span.transaction) { + return undefined; + } + + if (span.sampled) { + return undefined; + } + + if (!this.getClient()) { + return undefined; + } + + return this.captureEvent({ + contexts: { trace: span.getTraceContext() }, + spans: span.finishedSpans.filter(s => s !== span), + start_timestamp: span.startTimestamp, + timestamp: span.timestamp, + transaction: span.transaction, + type: 'transaction', + }); + } } /** Returns the global shim registry. */ diff --git a/packages/hub/src/scope.ts b/packages/hub/src/scope.ts index 968315aece41..43f9f17889f2 100644 --- a/packages/hub/src/scope.ts +++ b/packages/hub/src/scope.ts @@ -200,16 +200,6 @@ export class Scope implements ScopeInterface { return this; } - /** - * @inheritDoc - */ - public startSpan(parentSpan?: Span): Span { - const span = new Span(); - span.setParent(parentSpan); - this.setSpan(span); - return span; - } - /** * Internal getter for Span, used in Hub. * @hidden diff --git a/packages/hub/src/span.ts b/packages/hub/src/span.ts index fdb3781a8cc5..c5cf8f2c95de 100644 --- a/packages/hub/src/span.ts +++ b/packages/hub/src/span.ts @@ -1,4 +1,4 @@ -import { Span as SpanInterface } from '@sentry/types'; +import { Span as SpanInterface, SpanDetails } from '@sentry/types'; import { uuid4 } from '@sentry/utils'; export const TRACEPARENT_REGEXP = /^[ \t]*([0-9a-f]{32})?-?([0-9a-f]{16})?-?([01])?[ \t]*$/; @@ -7,26 +7,103 @@ export const TRACEPARENT_REGEXP = /^[ \t]*([0-9a-f]{32})?-?([0-9a-f]{16})?-?([01 * Span containg all data about a span */ export class Span implements SpanInterface { - public constructor( - private readonly _traceId: string = uuid4(), - private readonly _spanId: string = uuid4().substring(16), - private _sampled?: boolean, - private _parent?: Span, - ) {} + /** + * Trace ID + */ + private readonly _traceId: string = uuid4(); /** - * Setter for parent + * Span ID */ - public setParent(parent: Span | undefined): this { - this._parent = parent; - return this; + private readonly _spanId: string = uuid4().substring(16); + + /** + * Parent Span ID + */ + private readonly _parentSpanId?: string; + + /** + * Has the sampling decision been made? + */ + public readonly sampled?: string; + + /** + * Timestamp when the span was created. + */ + public readonly startTimestamp: number = new Date().getTime(); + + /** + * Finish timestamp of the span. + */ + public timestamp?: number; + + /** + * Set the transaction of the Span. + */ + public transaction?: string; + + /** + * Set the operation of the Span. + */ + public op?: string; + + /** + * Set the description of the Span. + */ + public description?: string; + + /** + * List of spans that were finalized + */ + public finishedSpans: Span[] = []; + + public constructor(spanDetails?: SpanDetails) { + if (!spanDetails) { + return this; + } + + if (spanDetails.traceId) { + this._traceId = spanDetails.traceId; + } + if (spanDetails.spanId) { + this._spanId = spanDetails.spanId; + } + if (spanDetails.parentSpanId) { + this._parentSpanId = spanDetails.parentSpanId; + } + if (spanDetails.sampled) { + this.sampled = spanDetails.sampled; + } + if (spanDetails.transaction) { + this.transaction = spanDetails.transaction; + } + if (spanDetails.op) { + this.op = spanDetails.op; + } + if (spanDetails.description) { + this.description = spanDetails.description; + } + } + + /** JSDoc */ + public newSpan(spanDetails?: Pick>): Span { + const span = new Span({ + ...spanDetails, + parentSpanId: this._parentSpanId, + sampled: this.sampled, + traceId: this._traceId, + }); + + span.finishedSpans = this.finishedSpans; + + return span; } /** - * Setter for sampled + * Setter for transaction. */ - public setSampled(sampled: boolean | undefined): this { - this._sampled = sampled; + public setTransaction(transaction: string | undefined): this { + this.transaction = transaction; return this; } @@ -34,33 +111,48 @@ export class Span implements SpanInterface { * Continues a trace * @param traceparent Traceparent string */ - public static fromTraceparent(traceparent: string): Span | undefined { + public static fromTraceparent( + traceparent: string, + spanDetails?: Pick>, + ): Span | undefined { const matches = traceparent.match(TRACEPARENT_REGEXP); if (matches) { - let sampled; - if (matches[3] === '1') { - sampled = true; - } else if (matches[3] === '0') { - sampled = false; - } - const parent = new Span(matches[1], matches[2], sampled); - return new Span(matches[1], undefined, sampled, parent); + const [traceId, spanId, sampled] = matches; + return new Span({ + ...spanDetails, + sampled, + spanId, + traceId, + }); } return undefined; } + /** + * Sets the finish timestamp on the current span + */ + public finish(): void { + this.timestamp = new Date().getTime(); + this.finishedSpans.push(this); + } + /** * @inheritDoc */ public toTraceparent(): string { - let sampled = ''; - if (this._sampled === true) { - sampled = '-1'; - } else if (this._sampled === false) { - sampled = '-0'; - } - - return `${this._traceId}-${this._spanId}${sampled}`; + return `${this._traceId}-${this._spanId}${this.sampled ? '-1' : '0'}`; + } + /** + * @inheritDoc + */ + public getTraceContext(): object { + return { + description: this.description, + op: this.op, + parent_span_id: this._parentSpanId, + span_id: this._spanId, + trace_id: this._traceId, + }; } /** @@ -68,10 +160,15 @@ export class Span implements SpanInterface { */ public toJSON(): object { return { - parent: (this._parent && this._parent.toJSON()) || undefined, - sampled: this._sampled, + description: this.description, + op: this.op, + parent_span_id: this._parentSpanId, + sampled: this.sampled, span_id: this._spanId, + start_timestamp: this.startTimestamp, + timestamp: this.timestamp, trace_id: this._traceId, + transaction: this.transaction, }; } } diff --git a/packages/hub/test/span.test.ts b/packages/hub/test/span.test.ts index 0ac3ab0244a2..6e05214ceea5 100644 --- a/packages/hub/test/span.test.ts +++ b/packages/hub/test/span.test.ts @@ -12,16 +12,16 @@ describe('Span', () => { expect(from._parent._spanId).toEqual('bbbbbbbbbbbbbbbb'); expect(from._traceId).toEqual('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); expect(from._spanId).not.toEqual('bbbbbbbbbbbbbbbb'); - expect(from._sampled).toBeUndefined(); + expect(from.sampled).toBeUndefined(); }); test('sample true', () => { const from = Span.fromTraceparent('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bbbbbbbbbbbbbbbb-1') as any; - expect(from._sampled).toBeTruthy(); + expect(from.sampled).toBeTruthy(); }); test('sample false', () => { const from = Span.fromTraceparent('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bbbbbbbbbbbbbbbb-0') as any; - expect(from._sampled).toBeFalsy(); + expect(from.sampled).toBeFalsy(); }); }); diff --git a/packages/integrations/src/tracing.ts b/packages/integrations/src/tracing.ts index f463b7a98182..ab5475610c76 100644 --- a/packages/integrations/src/tracing.ts +++ b/packages/integrations/src/tracing.ts @@ -75,7 +75,7 @@ export class Tracing implements Integration { */ public static startTrace(hub: Hub, transaction?: string): void { hub.configureScope(scope => { - scope.startSpan(); + // scope.startSpan(); scope.setTransaction(transaction); }); } diff --git a/packages/node/src/handlers.ts b/packages/node/src/handlers.ts index b9a72da7b394..3eab9be25c3e 100644 --- a/packages/node/src/handlers.ts +++ b/packages/node/src/handlers.ts @@ -1,5 +1,4 @@ -import { captureException, getCurrentHub, withScope } from '@sentry/core'; -import { Span } from '@sentry/hub'; +import { captureException, getCurrentHub } from '@sentry/core'; import { Event } from '@sentry/types'; import { forget, isString, logger, normalize } from '@sentry/utils'; import * as cookie from 'cookie'; @@ -321,20 +320,20 @@ export function errorHandler(options?: { ) => void { return function sentryErrorMiddleware( error: MiddlewareError, - _req: http.IncomingMessage, - _res: http.ServerResponse, + req: http.IncomingMessage, + res: http.ServerResponse, next: (error: MiddlewareError) => void, ): void { const shouldHandleError = (options && options.shouldHandleError) || defaultShouldHandleError; if (shouldHandleError(error)) { withScope(scope => { - if (_req.headers && isString(_req.headers['sentry-trace'])) { - const span = Span.fromTraceparent(_req.headers['sentry-trace'] as string); + if (req.headers && isString(req.headers['sentry-trace'])) { + const span = Span.fromTraceparent(req.headers['sentry-trace'] as string); scope.setSpan(span); } const eventId = captureException(error); - (_res as any).sentry = eventId; + (res as any).sentry = eventId; next(error); }); diff --git a/packages/node/test/manual/apm-transaction/main.js b/packages/node/test/manual/apm-transaction/main.js new file mode 100644 index 000000000000..c9c165668940 --- /dev/null +++ b/packages/node/test/manual/apm-transaction/main.js @@ -0,0 +1,112 @@ +const http = require('http'); +const express = require('express'); +const app = express(); +const Sentry = require('../../../dist'); + +Sentry.init({ + debug: true, + dsn: 'http://test@example.com/1337', + beforeSend(event) { + console.log(JSON.stringify(event, null, 2)); + return null; + }, +}); + +function hasSentryTraceHeader(req) { + return req.headers && typeof req.headers['sentry-trace'] === 'string'; +} + +class Tracing { + static start() { + return (req, _res, next) => { + const transaction = `${req.method.toUpperCase()} ${req.originalUrl}`; + const span = hasSentryTraceHeader(req) + ? Span.fromTraceparent(req.headers['sentry-trace'], { + transaction, + }) + : Sentry.getCurrentHub().startSpan({ + transaction, + }); + + Sentry.getCurrentHub().configureScope(scope => { + scope.setSpan(span); + }); + + next(); + }; + } + + static finish() { + return (_req, _res, next) => { + const scope = Sentry.getCurrentHub().getScope(); + if (!scope) { + return next(); + } + const span = scope.getSpan(); + if (!span) { + return next(); + } + Sentry.getCurrentHub().finishSpan(span); + next(); + }; + } +} + +async function databaseCall(_query) { + const span = Sentry.getCurrentHub().startSpan({ + op: 'db', + }); + + return new Promise(resolve => { + setTimeout(() => { + Sentry.getCurrentHub().finishSpan(span); + resolve('http://whatever.com/raw'); + }, Math.random() * 100); + }); +} + +async function httpCall(_url) { + const span = Sentry.getCurrentHub().startSpan({ + op: 'http', + }); + + return new Promise(resolve => { + setTimeout(() => { + Sentry.getCurrentHub().finishSpan(span); + resolve('httpCall'); + }, Math.random() * 100); + }); +} + +async function encodeData(_data) { + const span = Sentry.getCurrentHub().startSpan({ + op: 'encode', + }); + + return new Promise(resolve => { + setTimeout(() => { + Sentry.getCurrentHub().finishSpan(span); + resolve('encodedData'); + }, Math.random() * 100); + }); +} + +app.use(Sentry.Handlers.requestHandler()); +app.use(Tracing.start()); + +app.get('/trace', async (_req, res, next) => { + const url = await databaseCall('SELECT url FROM queue WHERE processed = 0 LIMIT 1'); + const raw = await httpCall(url); + const encoded = await encodeData(raw); + res.status(200).send(encoded); + next(); +}); + +app.use(Tracing.finish()); +app.use(Sentry.Handlers.errorHandler()); + +const server = app.listen(3000, () => { + http.get('http://localhost:3000/trace', res => { + server.close(); + }); +}); diff --git a/packages/types/src/event.ts b/packages/types/src/event.ts index 50a793cfbb30..d630356d8ce5 100644 --- a/packages/types/src/event.ts +++ b/packages/types/src/event.ts @@ -3,6 +3,7 @@ import { Exception } from './exception'; import { Request } from './request'; import { SdkInfo } from './sdkinfo'; import { Severity } from './severity'; +import { Span } from './span'; import { Stacktrace } from './stacktrace'; import { User } from './user'; @@ -11,6 +12,7 @@ export interface Event { event_id?: string; message?: string; timestamp?: number; + start_timestamp?: number; level?: Severity; platform?: string; logger?: string; @@ -33,10 +35,11 @@ export interface Event { extra?: { [key: string]: any }; user?: User; type?: EventType; + spans?: Span[]; } /** JSDoc */ -export type EventType = 'none'; +export type EventType = 'transaction'; /** JSDoc */ export interface EventHint { diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 57883c236499..3e1aa8842556 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -16,7 +16,7 @@ export { Response } from './response'; export { Scope } from './scope'; export { SdkInfo } from './sdkinfo'; export { Severity } from './severity'; -export { Span } from './span'; +export { Span, SpanDetails } from './span'; export { StackFrame } from './stackframe'; export { Stacktrace } from './stacktrace'; export { Status } from './status'; diff --git a/packages/types/src/scope.ts b/packages/types/src/scope.ts index 9f2c6fb6714c..aba75fb40230 100644 --- a/packages/types/src/scope.ts +++ b/packages/types/src/scope.ts @@ -76,11 +76,6 @@ export interface Scope { */ setSpan(span?: Span): this; - /** - * Starts a new Span. - */ - startSpan(): Span; - /** Clears the current scope and resets its properties. */ clear(): this; diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index 5d86766f798f..86fb332fcafa 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -2,6 +2,19 @@ export interface Span { /** Return a traceparent compatible header string */ toTraceparent(): string; + /** Convert the object to JSON for w. spans array info only */ + getTraceContext(): object; /** Convert the object to JSON */ toJSON(): object; } + +/** JSDoc */ +export interface SpanDetails { + description?: string; + op?: string; + parentSpanId?: string; + sampled?: string; + spanId?: string; + traceId?: string; + transaction?: string; +} From dd7bb41cd042aca59450718be757c9d81ed59c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Wed, 10 Jul 2019 15:30:56 +0200 Subject: [PATCH 02/63] Update tracing.ts and hub interface --- packages/integrations/src/tracing.ts | 7 +++++-- packages/types/src/hub.ts | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/integrations/src/tracing.ts b/packages/integrations/src/tracing.ts index ab5475610c76..c325587aed01 100644 --- a/packages/integrations/src/tracing.ts +++ b/packages/integrations/src/tracing.ts @@ -74,9 +74,12 @@ export class Tracing implements Integration { * @param transaction Optional transaction */ public static startTrace(hub: Hub, transaction?: string): void { + const span = hub.startSpan({ + transaction, + }); + hub.configureScope(scope => { - // scope.startSpan(); - scope.setTransaction(transaction); + scope.setSpan(span); }); } diff --git a/packages/types/src/hub.ts b/packages/types/src/hub.ts index 54d46fb88f9e..e59a4b694d48 100644 --- a/packages/types/src/hub.ts +++ b/packages/types/src/hub.ts @@ -4,6 +4,7 @@ import { Event, EventHint } from './event'; import { Integration, IntegrationClass } from './integration'; import { Scope } from './scope'; import { Severity } from './severity'; +import { Span, SpanDetails } from './span'; import { User } from './user'; /** @@ -170,4 +171,10 @@ export interface Hub { /** Returns all trace headers that are currently on the top scope. */ traceHeaders(): { [key: string]: string }; + + /** JSDoc */ + startSpan(spanDetails?: SpanDetails): Span; + + /** JSDoc */ + finishSpan(span: Span): string | undefined; } From 48da3f8375eecd699e114f7550f1cc9b6d6edc70 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Thu, 11 Jul 2019 15:47:51 +0200 Subject: [PATCH 03/63] feat: Some cleanup and changes --- packages/hub/src/hub.ts | 8 ++-- packages/hub/src/span.ts | 55 ++++++++++++---------------- packages/integrations/src/tracing.ts | 26 ------------- packages/types/src/hub.ts | 4 +- packages/types/src/index.ts | 2 +- packages/types/src/span.ts | 2 +- 6 files changed, 32 insertions(+), 65 deletions(-) diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index 4d21047c9166..20800b420e52 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -8,7 +8,7 @@ import { Integration, IntegrationClass, Severity, - SpanDetails, + SpanProps, User, } from '@sentry/types'; import { consoleSandbox, dynamicRequire, getGlobalObject, isNodeEnv, logger, uuid4 } from '@sentry/utils'; @@ -389,17 +389,17 @@ export class Hub implements HubInterface { /** * @inheritDoc */ - public startSpan(spanDetails?: SpanDetails): Span { + public startSpan(spanProps?: SpanProps): Span { const scope = this.getScope(); if (scope) { const span = scope.getSpan(); if (span) { - return span.newSpan(spanDetails); + return span.newSpan(spanProps); } } - return new Span(spanDetails); + return new Span(spanProps); } /** diff --git a/packages/hub/src/span.ts b/packages/hub/src/span.ts index c5cf8f2c95de..d14e44fb1f94 100644 --- a/packages/hub/src/span.ts +++ b/packages/hub/src/span.ts @@ -1,12 +1,12 @@ -import { Span as SpanInterface, SpanDetails } from '@sentry/types'; +import { Span as SpanInterface, SpanProps } from '@sentry/types'; import { uuid4 } from '@sentry/utils'; export const TRACEPARENT_REGEXP = /^[ \t]*([0-9a-f]{32})?-?([0-9a-f]{16})?-?([01])?[ \t]*$/; /** - * Span containg all data about a span + * Span contains all data about a span */ -export class Span implements SpanInterface { +export class Span implements SpanInterface, SpanProps { /** * Trace ID */ @@ -57,38 +57,38 @@ export class Span implements SpanInterface { */ public finishedSpans: Span[] = []; - public constructor(spanDetails?: SpanDetails) { - if (!spanDetails) { + public constructor(spanProps?: SpanProps) { + if (!spanProps) { return this; } - if (spanDetails.traceId) { - this._traceId = spanDetails.traceId; + if (spanProps.traceId) { + this._traceId = spanProps.traceId; } - if (spanDetails.spanId) { - this._spanId = spanDetails.spanId; + if (spanProps.spanId) { + this._spanId = spanProps.spanId; } - if (spanDetails.parentSpanId) { - this._parentSpanId = spanDetails.parentSpanId; + if (spanProps.parentSpanId) { + this._parentSpanId = spanProps.parentSpanId; } - if (spanDetails.sampled) { - this.sampled = spanDetails.sampled; + if (spanProps.sampled) { + this.sampled = spanProps.sampled; } - if (spanDetails.transaction) { - this.transaction = spanDetails.transaction; + if (spanProps.transaction) { + this.transaction = spanProps.transaction; } - if (spanDetails.op) { - this.op = spanDetails.op; + if (spanProps.op) { + this.op = spanProps.op; } - if (spanDetails.description) { - this.description = spanDetails.description; + if (spanProps.description) { + this.description = spanProps.description; } } /** JSDoc */ - public newSpan(spanDetails?: Pick>): Span { + public newSpan(spanProps?: Pick>): Span { const span = new Span({ - ...spanDetails, + ...spanProps, parentSpanId: this._parentSpanId, sampled: this.sampled, traceId: this._traceId, @@ -99,27 +99,19 @@ export class Span implements SpanInterface { return span; } - /** - * Setter for transaction. - */ - public setTransaction(transaction: string | undefined): this { - this.transaction = transaction; - return this; - } - /** * Continues a trace * @param traceparent Traceparent string */ public static fromTraceparent( traceparent: string, - spanDetails?: Pick>, + spanProps?: Pick>, ): Span | undefined { const matches = traceparent.match(TRACEPARENT_REGEXP); if (matches) { const [traceId, spanId, sampled] = matches; return new Span({ - ...spanDetails, + ...spanProps, sampled, spanId, traceId, @@ -142,6 +134,7 @@ export class Span implements SpanInterface { public toTraceparent(): string { return `${this._traceId}-${this._spanId}${this.sampled ? '-1' : '0'}`; } + /** * @inheritDoc */ diff --git a/packages/integrations/src/tracing.ts b/packages/integrations/src/tracing.ts index c325587aed01..7bbd2adc1e2c 100644 --- a/packages/integrations/src/tracing.ts +++ b/packages/integrations/src/tracing.ts @@ -6,7 +6,6 @@ interface TracingOptions { tracingOrigins?: Array; traceFetch?: boolean; traceXHR?: boolean; - autoStartOnDomReady?: boolean; } /** @@ -56,31 +55,6 @@ export class Tracing implements Integration { if (this._options.traceFetch !== false) { this._traceFetch(getCurrentHub); } - if (this._options.autoStartOnDomReady !== false) { - getGlobalObject().addEventListener('DOMContentLoaded', () => { - Tracing.startTrace(getCurrentHub(), getGlobalObject().location.href); - }); - getGlobalObject().document.onreadystatechange = () => { - if (document.readyState === 'complete') { - Tracing.startTrace(getCurrentHub(), getGlobalObject().location.href); - } - }; - } - } - - /** - * Starts a new trace - * @param hub The hub to start the trace on - * @param transaction Optional transaction - */ - public static startTrace(hub: Hub, transaction?: string): void { - const span = hub.startSpan({ - transaction, - }); - - hub.configureScope(scope => { - scope.setSpan(span); - }); } /** diff --git a/packages/types/src/hub.ts b/packages/types/src/hub.ts index e59a4b694d48..35e39e231da7 100644 --- a/packages/types/src/hub.ts +++ b/packages/types/src/hub.ts @@ -4,7 +4,7 @@ import { Event, EventHint } from './event'; import { Integration, IntegrationClass } from './integration'; import { Scope } from './scope'; import { Severity } from './severity'; -import { Span, SpanDetails } from './span'; +import { Span, SpanProps } from './span'; import { User } from './user'; /** @@ -173,7 +173,7 @@ export interface Hub { traceHeaders(): { [key: string]: string }; /** JSDoc */ - startSpan(spanDetails?: SpanDetails): Span; + startSpan(spanProps?: SpanProps): Span; /** JSDoc */ finishSpan(span: Span): string | undefined; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 3e1aa8842556..3b62fd27a781 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -16,7 +16,7 @@ export { Response } from './response'; export { Scope } from './scope'; export { SdkInfo } from './sdkinfo'; export { Severity } from './severity'; -export { Span, SpanDetails } from './span'; +export { Span, SpanProps } from './span'; export { StackFrame } from './stackframe'; export { Stacktrace } from './stacktrace'; export { Status } from './status'; diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index 86fb332fcafa..b158099f0f16 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -9,7 +9,7 @@ export interface Span { } /** JSDoc */ -export interface SpanDetails { +export interface SpanProps { description?: string; op?: string; parentSpanId?: string; From fe382e7dfe46e2bf1016f0baaf89f620570aa8cd Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Fri, 12 Jul 2019 13:41:10 +0200 Subject: [PATCH 04/63] feat: Add data/tags to span, Clear finishedSpans --- packages/hub/src/hub.ts | 10 ++++++++-- packages/hub/src/span.ts | 28 ++++++++++++++++++++++++---- packages/types/src/span.ts | 2 ++ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index 20800b420e52..1762ef7b4db0 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -422,14 +422,20 @@ export class Hub implements HubInterface { return undefined; } - return this.captureEvent({ + const finishedSpans = span.finishedSpans.filter(s => s !== span); + + const eventId = this.captureEvent({ contexts: { trace: span.getTraceContext() }, - spans: span.finishedSpans.filter(s => s !== span), + spans: finishedSpans, start_timestamp: span.startTimestamp, timestamp: span.timestamp, transaction: span.transaction, type: 'transaction', }); + + // After sending we reset the finishedSpans array + span.finishedSpans = []; + return eventId; } } diff --git a/packages/hub/src/span.ts b/packages/hub/src/span.ts index d14e44fb1f94..ee427b3af078 100644 --- a/packages/hub/src/span.ts +++ b/packages/hub/src/span.ts @@ -38,20 +38,30 @@ export class Span implements SpanInterface, SpanProps { public timestamp?: number; /** - * Set the transaction of the Span. + * Transaction of the Span. */ public transaction?: string; /** - * Set the operation of the Span. + * Operation of the Span. */ public op?: string; /** - * Set the description of the Span. + * Description of the Span. */ public description?: string; + /** + * Tags of the Span. + */ + public tags?: { [key: string]: string }; + + /** + * Data of the Span. + */ + public data?: { [key: string]: any }; + /** * List of spans that were finalized */ @@ -83,13 +93,19 @@ export class Span implements SpanInterface, SpanProps { if (spanProps.description) { this.description = spanProps.description; } + if (spanProps.data) { + this.data = spanProps.data; + } + if (spanProps.tags) { + this.tags = spanProps.tags; + } } /** JSDoc */ public newSpan(spanProps?: Pick>): Span { const span = new Span({ ...spanProps, - parentSpanId: this._parentSpanId, + parentSpanId: this._spanId, sampled: this.sampled, traceId: this._traceId, }); @@ -140,10 +156,12 @@ export class Span implements SpanInterface, SpanProps { */ public getTraceContext(): object { return { + data: this.data, description: this.description, op: this.op, parent_span_id: this._parentSpanId, span_id: this._spanId, + tags: this.tags, trace_id: this._traceId, }; } @@ -153,12 +171,14 @@ export class Span implements SpanInterface, SpanProps { */ public toJSON(): object { return { + data: this.data, description: this.description, op: this.op, parent_span_id: this._parentSpanId, sampled: this.sampled, span_id: this._spanId, start_timestamp: this.startTimestamp, + tags: this.tags, timestamp: this.timestamp, trace_id: this._traceId, transaction: this.transaction, diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index b158099f0f16..a9967c7748ab 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -17,4 +17,6 @@ export interface SpanProps { spanId?: string; traceId?: string; transaction?: string; + tags?: { [key: string]: string }; + data?: { [key: string]: any }; } From 8e8de119feb6685b21c4676ebe4cd65deb13f449 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Tue, 16 Jul 2019 14:38:14 +0200 Subject: [PATCH 05/63] fix: Sampled, parent span id and tests --- packages/hub/src/span.ts | 20 +++++++++++++++----- packages/hub/test/span.test.ts | 21 ++++++++++++--------- packages/types/src/span.ts | 2 +- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/packages/hub/src/span.ts b/packages/hub/src/span.ts index ee427b3af078..2775636f6d59 100644 --- a/packages/hub/src/span.ts +++ b/packages/hub/src/span.ts @@ -25,7 +25,7 @@ export class Span implements SpanInterface, SpanProps { /** * Has the sampling decision been made? */ - public readonly sampled?: string; + public readonly sampled?: boolean; /** * Timestamp when the span was created. @@ -125,12 +125,18 @@ export class Span implements SpanInterface, SpanProps { ): Span | undefined { const matches = traceparent.match(TRACEPARENT_REGEXP); if (matches) { - const [traceId, spanId, sampled] = matches; + let sampled: boolean | undefined; + if (matches[3] === '1') { + sampled = true; + } else if (matches[3] === '0') { + sampled = false; + } + return new Span({ ...spanProps, + parentSpanId: matches[2], sampled, - spanId, - traceId, + traceId: matches[1], }); } return undefined; @@ -148,7 +154,11 @@ export class Span implements SpanInterface, SpanProps { * @inheritDoc */ public toTraceparent(): string { - return `${this._traceId}-${this._spanId}${this.sampled ? '-1' : '0'}`; + let sampledString = ''; + if (this.sampled !== undefined) { + sampledString = this.sampled ? '-1' : '-0'; + } + return `${this._traceId}-${this._spanId}${sampledString}`; } /** diff --git a/packages/hub/test/span.test.ts b/packages/hub/test/span.test.ts index 6e05214ceea5..06e00a4eb4a5 100644 --- a/packages/hub/test/span.test.ts +++ b/packages/hub/test/span.test.ts @@ -8,8 +8,8 @@ describe('Span', () => { describe('fromTraceparent', () => { test('no sample', () => { const from = Span.fromTraceparent('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bbbbbbbbbbbbbbbb') as any; - expect(from._parent._traceId).toEqual('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); - expect(from._parent._spanId).toEqual('bbbbbbbbbbbbbbbb'); + + expect(from._parentSpanId).toEqual('bbbbbbbbbbbbbbbb'); expect(from._traceId).toEqual('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); expect(from._spanId).not.toEqual('bbbbbbbbbbbbbbbb'); expect(from.sampled).toBeUndefined(); @@ -30,16 +30,19 @@ describe('Span', () => { }); test('toJSON', () => { - expect(JSON.stringify(new Span('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbb'))).toEqual( - `{"span_id":"bbbbbbbbbbbbbbbb","trace_id":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}`, + const span = JSON.parse( + JSON.stringify(new Span({ traceId: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', spanId: 'bbbbbbbbbbbbbbbb' })), ); + expect(span).toHaveProperty('span_id', 'bbbbbbbbbbbbbbbb'); + expect(span).toHaveProperty('trace_id', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); }); test('toJSON with parent', () => { - const spanA = new Span('a', 'b'); - const spanB = new Span('c', 'd', false, spanA); - expect(JSON.stringify(spanB)).toEqual( - `{"parent":{"span_id":"b","trace_id":"a"},"sampled":false,"span_id":"d","trace_id":"c"}`, - ); + const spanA = new Span({ traceId: 'a', spanId: 'b' }) as any; + const spanB = new Span({ traceId: 'c', spanId: 'd', sampled: false, parentSpanId: spanA._spanId }); + const serialized = JSON.parse(JSON.stringify(spanB)); + expect(serialized).toHaveProperty('parent_span_id', 'b'); + expect(serialized).toHaveProperty('span_id', 'd'); + expect(serialized).toHaveProperty('trace_id', 'c'); }); }); diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index a9967c7748ab..e7b0dbbcffbe 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -13,7 +13,7 @@ export interface SpanProps { description?: string; op?: string; parentSpanId?: string; - sampled?: string; + sampled?: boolean; spanId?: string; traceId?: string; transaction?: string; From b34e42d523c5560e924f89cb12da33314d19678d Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Tue, 16 Jul 2019 15:07:42 +0200 Subject: [PATCH 06/63] fix: Sampled spans --- packages/hub/src/hub.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index 1762ef7b4db0..f635fcabfcbc 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -414,14 +414,12 @@ export class Hub implements HubInterface { return undefined; } - if (span.sampled) { - return undefined; - } - if (!this.getClient()) { return undefined; } + // TODO: if sampled do what? + const finishedSpans = span.finishedSpans.filter(s => s !== span); const eventId = this.captureEvent({ From 4db1f1908ed2b8944c5a3d353df34d39a74992c4 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 17 Jul 2019 11:56:50 +0200 Subject: [PATCH 07/63] fix: Detect internal sentry requests --- packages/core/src/api.ts | 2 +- packages/hub/test/span.test.ts | 12 +++++++++++ packages/integrations/src/tracing.ts | 31 ++++++++++++++++++++-------- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/packages/core/src/api.ts b/packages/core/src/api.ts index 8457e0922cfd..7057fc1b67b1 100644 --- a/packages/core/src/api.ts +++ b/packages/core/src/api.ts @@ -28,7 +28,7 @@ export class API { public getStoreEndpointWithUrlEncodedAuth(): string { const dsn = this._dsnObject; const auth = { - sentry_key: dsn.user, + sentry_key: dsn.user, // sentry_key is currently used in tracing integration to identify internal sentry requests sentry_version: SENTRY_API_VERSION, }; // Auth is intentionally sent as part of query string (NOT as custom HTTP header) diff --git a/packages/hub/test/span.test.ts b/packages/hub/test/span.test.ts index 06e00a4eb4a5..e5cf733440b4 100644 --- a/packages/hub/test/span.test.ts +++ b/packages/hub/test/span.test.ts @@ -23,6 +23,18 @@ describe('Span', () => { const from = Span.fromTraceparent('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bbbbbbbbbbbbbbbb-0') as any; expect(from.sampled).toBeFalsy(); }); + + test('just sample rate', () => { + const from = Span.fromTraceparent('0') as any; + expect(from._traceId).toHaveLength(32); + expect(from._spanId).toHaveLength(16); + expect(from.sampled).toBeFalsy(); + + const from2 = Span.fromTraceparent('1') as any; + expect(from2._traceId).toHaveLength(32); + expect(from2._spanId).toHaveLength(16); + expect(from2.sampled).toBeTruthy(); + }); }); test('fromTraceparent - invalid', () => { diff --git a/packages/integrations/src/tracing.ts b/packages/integrations/src/tracing.ts index 7bbd2adc1e2c..2619c209371f 100644 --- a/packages/integrations/src/tracing.ts +++ b/packages/integrations/src/tracing.ts @@ -93,10 +93,16 @@ export class Tracing implements Integration { const url = self._xhrUrl; const headers = getCurrentHub().traceHeaders(); // tslint:disable-next-line: prefer-for-of - const isWhitelisted = self._options.tracingOrigins.some((origin: string | RegExp) => + let isWhitelisted = self._options.tracingOrigins.some((origin: string | RegExp) => isMatchingPattern(url, origin), ); + if (isMatchingPattern(url, 'sentry_key')) { + // If sentry_key is in the url, it's an internal store request to sentry + // we do not want to add the trace header to store requests + isWhitelisted = false; + } + if (isWhitelisted && this.setRequestHeader) { Object.keys(headers).forEach(key => { this.setRequestHeader(key, headers[key]); @@ -121,30 +127,37 @@ export class Tracing implements Integration { fill(getGlobalObject(), 'fetch', function(originalFetch: () => void): () => void { return function(...args: any[]): void { // @ts-ignore - const self = getCurrentHub().getIntegration(Tracing); + const hub = getCurrentHub(); + const self = hub.getIntegration(Tracing); if (self && self._options.tracingOrigins) { const url = args[0] as string; const options = (args[1] = (args[1] as { [key: string]: any }) || {}); - let whiteListed = false; + let isWhitelisted = false; self._options.tracingOrigins.forEach((whiteListUrl: string | RegExp) => { - if (!whiteListed) { - whiteListed = isMatchingPattern(url, whiteListUrl); + if (!isWhitelisted) { + isWhitelisted = isMatchingPattern(url, whiteListUrl); } }); - if (whiteListed) { + if (isMatchingPattern(url, 'sentry_key')) { + // If sentry_key is in the url, it's an internal store request to sentry + // we do not want to add the trace header to store requests + isWhitelisted = false; + } + + if (isWhitelisted) { if (options.headers) { if (Array.isArray(options.headers)) { - options.headers = [...options.headers, ...Object.entries(getCurrentHub().traceHeaders())]; + options.headers = [...options.headers, ...Object.entries(hub.traceHeaders())]; } else { options.headers = { ...options.headers, - ...getCurrentHub().traceHeaders(), + ...hub.traceHeaders(), }; } } else { - options.headers = getCurrentHub().traceHeaders(); + options.headers = hub.traceHeaders(); } } } From b3f0ed221ab5d5e25789dd5a3fa2da937774c35e Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Thu, 18 Jul 2019 11:59:26 +0200 Subject: [PATCH 08/63] meta: Changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6858d1696f77..a154037090a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## Unreleased - Coming soon... +- [hub] feat: Add more span functions (#2161) +- [integrations] feat: Change `Tracing` integration (#2161) ## 5.7.1 From 59516ce583b43bc64de9e730af73d2462729f02f Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Tue, 23 Jul 2019 11:07:40 +0200 Subject: [PATCH 09/63] ref: Rename SpanProps to SpanContext --- packages/hub/src/hub.ts | 8 +++--- packages/hub/src/span.ts | 52 ++++++++++++++++++------------------- packages/types/src/hub.ts | 4 +-- packages/types/src/index.ts | 2 +- packages/types/src/span.ts | 2 +- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index f635fcabfcbc..4ec785cb99e3 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -8,7 +8,7 @@ import { Integration, IntegrationClass, Severity, - SpanProps, + SpanContext, User, } from '@sentry/types'; import { consoleSandbox, dynamicRequire, getGlobalObject, isNodeEnv, logger, uuid4 } from '@sentry/utils'; @@ -389,17 +389,17 @@ export class Hub implements HubInterface { /** * @inheritDoc */ - public startSpan(spanProps?: SpanProps): Span { + public startSpan(SpanContext?: SpanContext): Span { const scope = this.getScope(); if (scope) { const span = scope.getSpan(); if (span) { - return span.newSpan(spanProps); + return span.newSpan(SpanContext); } } - return new Span(spanProps); + return new Span(SpanContext); } /** diff --git a/packages/hub/src/span.ts b/packages/hub/src/span.ts index 2775636f6d59..f01638c4e5bc 100644 --- a/packages/hub/src/span.ts +++ b/packages/hub/src/span.ts @@ -1,4 +1,4 @@ -import { Span as SpanInterface, SpanProps } from '@sentry/types'; +import { Span as SpanInterface, SpanContext } from '@sentry/types'; import { uuid4 } from '@sentry/utils'; export const TRACEPARENT_REGEXP = /^[ \t]*([0-9a-f]{32})?-?([0-9a-f]{16})?-?([01])?[ \t]*$/; @@ -6,7 +6,7 @@ export const TRACEPARENT_REGEXP = /^[ \t]*([0-9a-f]{32})?-?([0-9a-f]{16})?-?([01 /** * Span contains all data about a span */ -export class Span implements SpanInterface, SpanProps { +export class Span implements SpanInterface, SpanContext { /** * Trace ID */ @@ -67,44 +67,44 @@ export class Span implements SpanInterface, SpanProps { */ public finishedSpans: Span[] = []; - public constructor(spanProps?: SpanProps) { - if (!spanProps) { + public constructor(SpanContext?: SpanContext) { + if (!SpanContext) { return this; } - if (spanProps.traceId) { - this._traceId = spanProps.traceId; + if (SpanContext.traceId) { + this._traceId = SpanContext.traceId; } - if (spanProps.spanId) { - this._spanId = spanProps.spanId; + if (SpanContext.spanId) { + this._spanId = SpanContext.spanId; } - if (spanProps.parentSpanId) { - this._parentSpanId = spanProps.parentSpanId; + if (SpanContext.parentSpanId) { + this._parentSpanId = SpanContext.parentSpanId; } - if (spanProps.sampled) { - this.sampled = spanProps.sampled; + if (SpanContext.sampled) { + this.sampled = SpanContext.sampled; } - if (spanProps.transaction) { - this.transaction = spanProps.transaction; + if (SpanContext.transaction) { + this.transaction = SpanContext.transaction; } - if (spanProps.op) { - this.op = spanProps.op; + if (SpanContext.op) { + this.op = SpanContext.op; } - if (spanProps.description) { - this.description = spanProps.description; + if (SpanContext.description) { + this.description = SpanContext.description; } - if (spanProps.data) { - this.data = spanProps.data; + if (SpanContext.data) { + this.data = SpanContext.data; } - if (spanProps.tags) { - this.tags = spanProps.tags; + if (SpanContext.tags) { + this.tags = SpanContext.tags; } } /** JSDoc */ - public newSpan(spanProps?: Pick>): Span { + public newSpan(SpanContext?: Pick>): Span { const span = new Span({ - ...spanProps, + ...SpanContext, parentSpanId: this._spanId, sampled: this.sampled, traceId: this._traceId, @@ -121,7 +121,7 @@ export class Span implements SpanInterface, SpanProps { */ public static fromTraceparent( traceparent: string, - spanProps?: Pick>, + SpanContext?: Pick>, ): Span | undefined { const matches = traceparent.match(TRACEPARENT_REGEXP); if (matches) { @@ -133,7 +133,7 @@ export class Span implements SpanInterface, SpanProps { } return new Span({ - ...spanProps, + ...SpanContext, parentSpanId: matches[2], sampled, traceId: matches[1], diff --git a/packages/types/src/hub.ts b/packages/types/src/hub.ts index 35e39e231da7..6b1b0516ad3f 100644 --- a/packages/types/src/hub.ts +++ b/packages/types/src/hub.ts @@ -4,7 +4,7 @@ import { Event, EventHint } from './event'; import { Integration, IntegrationClass } from './integration'; import { Scope } from './scope'; import { Severity } from './severity'; -import { Span, SpanProps } from './span'; +import { Span, SpanContext } from './span'; import { User } from './user'; /** @@ -173,7 +173,7 @@ export interface Hub { traceHeaders(): { [key: string]: string }; /** JSDoc */ - startSpan(spanProps?: SpanProps): Span; + startSpan(SpanContext?: SpanContext): Span; /** JSDoc */ finishSpan(span: Span): string | undefined; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 3b62fd27a781..738782e52626 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -16,7 +16,7 @@ export { Response } from './response'; export { Scope } from './scope'; export { SdkInfo } from './sdkinfo'; export { Severity } from './severity'; -export { Span, SpanProps } from './span'; +export { Span, SpanContext } from './span'; export { StackFrame } from './stackframe'; export { Stacktrace } from './stacktrace'; export { Status } from './status'; diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index e7b0dbbcffbe..2efb4c9c20fd 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -9,7 +9,7 @@ export interface Span { } /** JSDoc */ -export interface SpanProps { +export interface SpanContext { description?: string; op?: string; parentSpanId?: string; From cff9c0ed2c3f73e09e543ace5db78f76eca96680 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Tue, 23 Jul 2019 16:29:42 +0200 Subject: [PATCH 10/63] fix: SpanContext var name, Timestamp in secs --- packages/hub/src/hub.ts | 6 ++--- packages/hub/src/span.ts | 52 +++++++++++++++++++-------------------- packages/types/src/hub.ts | 2 +- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index 4ec785cb99e3..03e73bfd3262 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -389,17 +389,17 @@ export class Hub implements HubInterface { /** * @inheritDoc */ - public startSpan(SpanContext?: SpanContext): Span { + public startSpan(spanContext?: SpanContext): Span { const scope = this.getScope(); if (scope) { const span = scope.getSpan(); if (span) { - return span.newSpan(SpanContext); + return span.newSpan(spanContext); } } - return new Span(SpanContext); + return new Span(spanContext); } /** diff --git a/packages/hub/src/span.ts b/packages/hub/src/span.ts index f01638c4e5bc..07c9af253acd 100644 --- a/packages/hub/src/span.ts +++ b/packages/hub/src/span.ts @@ -30,7 +30,7 @@ export class Span implements SpanInterface, SpanContext { /** * Timestamp when the span was created. */ - public readonly startTimestamp: number = new Date().getTime(); + public readonly startTimestamp: number = new Date().getTime() / 1000; /** * Finish timestamp of the span. @@ -67,44 +67,44 @@ export class Span implements SpanInterface, SpanContext { */ public finishedSpans: Span[] = []; - public constructor(SpanContext?: SpanContext) { - if (!SpanContext) { + public constructor(spanContext?: SpanContext) { + if (!spanContext) { return this; } - if (SpanContext.traceId) { - this._traceId = SpanContext.traceId; + if (spanContext.traceId) { + this._traceId = spanContext.traceId; } - if (SpanContext.spanId) { - this._spanId = SpanContext.spanId; + if (spanContext.spanId) { + this._spanId = spanContext.spanId; } - if (SpanContext.parentSpanId) { - this._parentSpanId = SpanContext.parentSpanId; + if (spanContext.parentSpanId) { + this._parentSpanId = spanContext.parentSpanId; } - if (SpanContext.sampled) { - this.sampled = SpanContext.sampled; + if (spanContext.sampled) { + this.sampled = spanContext.sampled; } - if (SpanContext.transaction) { - this.transaction = SpanContext.transaction; + if (spanContext.transaction) { + this.transaction = spanContext.transaction; } - if (SpanContext.op) { - this.op = SpanContext.op; + if (spanContext.op) { + this.op = spanContext.op; } - if (SpanContext.description) { - this.description = SpanContext.description; + if (spanContext.description) { + this.description = spanContext.description; } - if (SpanContext.data) { - this.data = SpanContext.data; + if (spanContext.data) { + this.data = spanContext.data; } - if (SpanContext.tags) { - this.tags = SpanContext.tags; + if (spanContext.tags) { + this.tags = spanContext.tags; } } /** JSDoc */ - public newSpan(SpanContext?: Pick>): Span { + public newSpan(spanContext?: Pick>): Span { const span = new Span({ - ...SpanContext, + ...spanContext, parentSpanId: this._spanId, sampled: this.sampled, traceId: this._traceId, @@ -121,7 +121,7 @@ export class Span implements SpanInterface, SpanContext { */ public static fromTraceparent( traceparent: string, - SpanContext?: Pick>, + spanContext?: Pick>, ): Span | undefined { const matches = traceparent.match(TRACEPARENT_REGEXP); if (matches) { @@ -133,7 +133,7 @@ export class Span implements SpanInterface, SpanContext { } return new Span({ - ...SpanContext, + ...spanContext, parentSpanId: matches[2], sampled, traceId: matches[1], @@ -146,7 +146,7 @@ export class Span implements SpanInterface, SpanContext { * Sets the finish timestamp on the current span */ public finish(): void { - this.timestamp = new Date().getTime(); + this.timestamp = new Date().getTime() / 1000; this.finishedSpans.push(this); } diff --git a/packages/types/src/hub.ts b/packages/types/src/hub.ts index 6b1b0516ad3f..5abe93b81858 100644 --- a/packages/types/src/hub.ts +++ b/packages/types/src/hub.ts @@ -173,7 +173,7 @@ export interface Hub { traceHeaders(): { [key: string]: string }; /** JSDoc */ - startSpan(SpanContext?: SpanContext): Span; + startSpan(spanContext?: SpanContext): Span; /** JSDoc */ finishSpan(span: Span): string | undefined; From 41c974ceed8a6115b920460c3c4b39bd76670010 Mon Sep 17 00:00:00 2001 From: HazA Date: Tue, 23 Jul 2019 22:27:00 +0200 Subject: [PATCH 11/63] feat: Add simple API, timestampWithMs helper --- packages/hub/src/hub.ts | 27 ++++++++++++++++++++------- packages/hub/src/scope.ts | 4 ++-- packages/hub/src/span.ts | 32 +++++++++++++++++--------------- packages/minimal/src/index.ts | 27 ++++++++++++++++++++++++++- packages/types/src/hub.ts | 21 ++++++++++++++++++--- packages/types/src/span.ts | 30 +++++++++++++++++++++++++++++- packages/utils/src/misc.ts | 7 +++++++ 7 files changed, 119 insertions(+), 29 deletions(-) diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index 03e73bfd3262..70f031d9bd03 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -11,7 +11,15 @@ import { SpanContext, User, } from '@sentry/types'; -import { consoleSandbox, dynamicRequire, getGlobalObject, isNodeEnv, logger, uuid4 } from '@sentry/utils'; +import { + consoleSandbox, + dynamicRequire, + getGlobalObject, + isNodeEnv, + logger, + timestampWithMs, + uuid4, +} from '@sentry/utils'; import { Carrier, Layer } from './interfaces'; import { Scope } from './scope'; @@ -253,7 +261,7 @@ export class Hub implements HubInterface { return; } - const timestamp = new Date().getTime() / 1000; + const timestamp = timestampWithMs(); const mergedBreadcrumb = { timestamp, ...breadcrumb }; const finalBreadcrumb = beforeBreadcrumb ? (consoleSandbox(() => beforeBreadcrumb(mergedBreadcrumb, hint)) as Breadcrumb | null) @@ -389,17 +397,22 @@ export class Hub implements HubInterface { /** * @inheritDoc */ - public startSpan(spanContext?: SpanContext): Span { - const scope = this.getScope(); + public startSpan(spanContext?: SpanContext, bindOnScope: boolean = false): Span { + const top = this.getStackTop(); - if (scope) { - const span = scope.getSpan(); + const simpleNewSpan = new Span(spanContext); + if (top.scope && top.client) { + if (bindOnScope) { + top.scope.setSpan(simpleNewSpan); + return simpleNewSpan; + } + const span = top.scope.getSpan(); if (span) { return span.newSpan(spanContext); } } - return new Span(spanContext); + return simpleNewSpan; } /** diff --git a/packages/hub/src/scope.ts b/packages/hub/src/scope.ts index 43f9f17889f2..54ffde8bb73b 100644 --- a/packages/hub/src/scope.ts +++ b/packages/hub/src/scope.ts @@ -1,5 +1,5 @@ import { Breadcrumb, Event, EventHint, EventProcessor, Scope as ScopeInterface, Severity, User } from '@sentry/types'; -import { getGlobalObject, isThenable, normalize, SyncPromise } from '@sentry/utils'; +import { getGlobalObject, isThenable, normalize, SyncPromise, timestampWithMs } from '@sentry/utils'; import { Span } from './span'; @@ -250,7 +250,7 @@ export class Scope implements ScopeInterface { * @inheritDoc */ public addBreadcrumb(breadcrumb: Breadcrumb, maxBreadcrumbs?: number): this { - const timestamp = new Date().getTime() / 1000; + const timestamp = timestampWithMs(); const mergedBreadcrumb = { timestamp, ...breadcrumb }; this._breadcrumbs = diff --git a/packages/hub/src/span.ts b/packages/hub/src/span.ts index 07c9af253acd..ddec1def03a0 100644 --- a/packages/hub/src/span.ts +++ b/packages/hub/src/span.ts @@ -1,5 +1,5 @@ import { Span as SpanInterface, SpanContext } from '@sentry/types'; -import { uuid4 } from '@sentry/utils'; +import { timestampWithMs, uuid4 } from '@sentry/utils'; export const TRACEPARENT_REGEXP = /^[ \t]*([0-9a-f]{32})?-?([0-9a-f]{16})?-?([01])?[ \t]*$/; @@ -8,29 +8,29 @@ export const TRACEPARENT_REGEXP = /^[ \t]*([0-9a-f]{32})?-?([0-9a-f]{16})?-?([01 */ export class Span implements SpanInterface, SpanContext { /** - * Trace ID + * @inheritDoc */ private readonly _traceId: string = uuid4(); /** - * Span ID + * @inheritDoc */ private readonly _spanId: string = uuid4().substring(16); /** - * Parent Span ID + * @inheritDoc */ private readonly _parentSpanId?: string; /** - * Has the sampling decision been made? + * @inheritDoc */ public readonly sampled?: boolean; /** * Timestamp when the span was created. */ - public readonly startTimestamp: number = new Date().getTime() / 1000; + public readonly startTimestamp: number = timestampWithMs(); /** * Finish timestamp of the span. @@ -38,27 +38,27 @@ export class Span implements SpanInterface, SpanContext { public timestamp?: number; /** - * Transaction of the Span. + * @inheritDoc */ public transaction?: string; /** - * Operation of the Span. + * @inheritDoc */ public op?: string; /** - * Description of the Span. + * @inheritDoc */ public description?: string; /** - * Tags of the Span. + * @inheritDoc */ public tags?: { [key: string]: string }; /** - * Data of the Span. + * @inheritDoc */ public data?: { [key: string]: any }; @@ -101,7 +101,10 @@ export class Span implements SpanInterface, SpanContext { } } - /** JSDoc */ + /** + * Creates a new `Span` while setting the current `Span.id` as `parentSpanId`. + * Also the `sampled` decision will be inherited. + */ public newSpan(spanContext?: Pick>): Span { const span = new Span({ ...spanContext, @@ -116,7 +119,7 @@ export class Span implements SpanInterface, SpanContext { } /** - * Continues a trace + * Continues a trace from a string (usually the header). * @param traceparent Traceparent string */ public static fromTraceparent( @@ -131,7 +134,6 @@ export class Span implements SpanInterface, SpanContext { } else if (matches[3] === '0') { sampled = false; } - return new Span({ ...spanContext, parentSpanId: matches[2], @@ -146,7 +148,7 @@ export class Span implements SpanInterface, SpanContext { * Sets the finish timestamp on the current span */ public finish(): void { - this.timestamp = new Date().getTime() / 1000; + this.timestamp = timestampWithMs(); this.finishedSpans.push(this); } diff --git a/packages/minimal/src/index.ts b/packages/minimal/src/index.ts index adcd68fd78ba..acbf9adfc244 100644 --- a/packages/minimal/src/index.ts +++ b/packages/minimal/src/index.ts @@ -1,5 +1,5 @@ import { getCurrentHub, Hub, Scope } from '@sentry/hub'; -import { Breadcrumb, Event, Severity, User } from '@sentry/types'; +import { Breadcrumb, Event, Severity, Span, SpanContext, User } from '@sentry/types'; /** * This calls a function on the current hub. @@ -166,3 +166,28 @@ export function withScope(callback: (scope: Scope) => void): void { export function _callOnClient(method: string, ...args: any[]): void { callOnHub('_invokeClient', method, ...args); } + +/** + * This functions starts a span. If just a `SpanContext` is passed and there is already a Span + * on the Scope, the created Span will have a reference to the one on the Scope. + * If a Span is on the current Scope it is considered a `transaction`. + * When using the second parameter it will set the created Span on the Scope (replacing whats there). + * This can be used as a shortcut to not set it manually on the Scope. + * + * @param spanContext Properties with which the span should be created + * @param bindOnScope Determines if the started span will be set on the Scope + */ +export function startSpan(spanContext?: SpanContext, bindOnScope?: boolean): Span { + return callOnHub('startSpan', spanContext, bindOnScope); +} + +/** + * This finishes the passed `Span`. If the `Span` has the property `transaction` set and it's bound on the + * current Scope, an `transaction` Event will be sent to Sentry containing all finished Spans inbetween. + * Returns either an `event.id` or `undefined` in case event wasn't sent. + * + * @param span `Span` instance that was created by {@link startSpan} + */ +export function finishSpan(span: Span): string | undefined { + return callOnHub('startSpan', span); +} diff --git a/packages/types/src/hub.ts b/packages/types/src/hub.ts index 5abe93b81858..b873f38ebbdc 100644 --- a/packages/types/src/hub.ts +++ b/packages/types/src/hub.ts @@ -172,9 +172,24 @@ export interface Hub { /** Returns all trace headers that are currently on the top scope. */ traceHeaders(): { [key: string]: string }; - /** JSDoc */ - startSpan(spanContext?: SpanContext): Span; + /** + * This functions starts a span. If just a `SpanContext` is passed and there is already a Span + * on the Scope, the created Span will have a reference to the one on the Scope. + * If a Span is on the current Scope it is considered a `transaction`. + * When using the second parameter it will set the created Span on the Scope (replacing whats there). + * This can be used as a shortcut to not set it manually on the Scope. + * + * @param spanContext Properties with which the span should be created + * @param bindOnScope Determines if the started span will be set on the Scope + */ + startSpan(spanContext?: SpanContext, bindOnScope?: boolean): Span; - /** JSDoc */ + /** + * This finishes the passed `Span`. If the `Span` has the property `transaction` set and it's bound on the + * current Scope, an `transaction` Event will be sent to Sentry containing all finished Spans inbetween. + * Returns either an `event.id` or `undefined` in case event wasn't sent. + * + * @param span `Span` instance that was created by {@link startSpan} + */ finishSpan(span: Span): string | undefined; } diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index 2efb4c9c20fd..ec08adc4a6f8 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -8,15 +8,43 @@ export interface Span { toJSON(): object; } -/** JSDoc */ +/** Interface holder all properties that can be set on a Span on creation. */ export interface SpanContext { + /** + * Description of the Span. + */ description?: string; + /** + * Operation of the Span. + */ op?: string; + /** + * Parent Span ID + */ parentSpanId?: string; + /** + * Has the sampling decision been made? + */ sampled?: boolean; + /** + * Span ID + */ spanId?: string; + /** + * Trace ID + */ traceId?: string; + /** + * Transaction of the Span. + */ transaction?: string; + /** + * Tags of the Span. + */ tags?: { [key: string]: string }; + + /** + * Data of the Span. + */ data?: { [key: string]: any }; } diff --git a/packages/utils/src/misc.ts b/packages/utils/src/misc.ts index d6b3f35a9546..30e1d741b298 100644 --- a/packages/utils/src/misc.ts +++ b/packages/utils/src/misc.ts @@ -335,3 +335,10 @@ function _htmlElementAsString(elem: HTMLElement): string { } return out.join(''); } + +/** + * Returns a timestamp in seconds with milliseconds precision. + */ +export function timestampWithMs(): number { + return new Date().getTime() / 1000; +} From 494a6f49006555e4d26eb9012729d7ec727992a4 Mon Sep 17 00:00:00 2001 From: HazA Date: Tue, 23 Jul 2019 22:37:00 +0200 Subject: [PATCH 12/63] fix: Use timestampWithMs --- packages/core/src/api.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/api.ts b/packages/core/src/api.ts index 7057fc1b67b1..b6a8c09bb500 100644 --- a/packages/core/src/api.ts +++ b/packages/core/src/api.ts @@ -1,5 +1,5 @@ import { DsnLike } from '@sentry/types'; -import { urlEncode } from '@sentry/utils'; +import { timestampWithMs, urlEncode } from '@sentry/utils'; import { Dsn } from './dsn'; @@ -54,7 +54,7 @@ export class API { public getRequestHeaders(clientName: string, clientVersion: string): { [key: string]: string } { const dsn = this._dsnObject; const header = [`Sentry sentry_version=${SENTRY_API_VERSION}`]; - header.push(`sentry_timestamp=${new Date().getTime()}`); + header.push(`sentry_timestamp=${timestampWithMs()}`); header.push(`sentry_client=${clientName}/${clientVersion}`); header.push(`sentry_key=${dsn.user}`); if (dsn.pass) { From 790ac56bde8b9b71927f676bcd218f5c89316538 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 24 Jul 2019 11:11:15 +0200 Subject: [PATCH 13/63] feat: Expose minimal API --- packages/browser/src/index.ts | 2 ++ packages/core/src/index.ts | 2 ++ packages/hub/src/hub.ts | 40 +++++++++++++++++++++++++---------- packages/minimal/src/index.ts | 3 ++- packages/node/src/index.ts | 4 +++- packages/types/src/hub.ts | 2 +- 6 files changed, 39 insertions(+), 14 deletions(-) diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index a9fa8558bd28..db4904801795 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -20,6 +20,7 @@ export { captureEvent, captureMessage, configureScope, + finishSpan, getHubFromCarrier, getCurrentHub, Hub, @@ -30,6 +31,7 @@ export { setTag, setTags, setUser, + startSpan, Span, withScope, } from '@sentry/core'; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index f2276b481ff2..37a44e134760 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -4,12 +4,14 @@ export { captureEvent, captureMessage, configureScope, + finishSpan, setContext, setExtra, setExtras, setTag, setTags, setUser, + startSpan, withScope, } from '@sentry/minimal'; export { addGlobalEventProcessor, getCurrentHub, getHubFromCarrier, Hub, Scope, Span } from '@sentry/hub'; diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index 70f031d9bd03..f95840b506bb 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -418,34 +418,52 @@ export class Hub implements HubInterface { /** * @inheritDoc */ - public finishSpan(span: Span): string | undefined { - if (!span.timestamp) { - span.finish(); + public finishSpan(span?: Span): string | undefined { + const top = this.getStackTop(); + let passedSpan = span; + + // If the passed span is undefined we try to get the span from the scope and finish it. + if (passedSpan === undefined) { + if (top.scope && top.client) { + const scopeSpan = top.scope.getSpan(); + if (scopeSpan) { + passedSpan = scopeSpan; + } + } + } + + if (passedSpan === undefined) { + // We will do nothing since nothing was passed and there is no Span on the scope. + return undefined; + } + + if (!passedSpan.timestamp) { + passedSpan.finish(); } - if (!span.transaction) { + if (!passedSpan.transaction) { return undefined; } - if (!this.getClient()) { + if (!top.client) { return undefined; } // TODO: if sampled do what? - const finishedSpans = span.finishedSpans.filter(s => s !== span); + const finishedSpans = passedSpan.finishedSpans.filter(s => s !== span); const eventId = this.captureEvent({ - contexts: { trace: span.getTraceContext() }, + contexts: { trace: passedSpan.getTraceContext() }, spans: finishedSpans, - start_timestamp: span.startTimestamp, - timestamp: span.timestamp, - transaction: span.transaction, + start_timestamp: passedSpan.startTimestamp, + timestamp: passedSpan.timestamp, + transaction: passedSpan.transaction, type: 'transaction', }); // After sending we reset the finishedSpans array - span.finishedSpans = []; + passedSpan.finishedSpans = []; return eventId; } } diff --git a/packages/minimal/src/index.ts b/packages/minimal/src/index.ts index acbf9adfc244..5b47d86003eb 100644 --- a/packages/minimal/src/index.ts +++ b/packages/minimal/src/index.ts @@ -162,6 +162,7 @@ export function withScope(callback: (scope: Scope) => void): void { * * @param method The method to call on the client/client. * @param args Arguments to pass to the client/fontend. + * @hidden */ export function _callOnClient(method: string, ...args: any[]): void { callOnHub('_invokeClient', method, ...args); @@ -188,6 +189,6 @@ export function startSpan(spanContext?: SpanContext, bindOnScope?: boolean): Spa * * @param span `Span` instance that was created by {@link startSpan} */ -export function finishSpan(span: Span): string | undefined { +export function finishSpan(span?: Span): string | undefined { return callOnHub('startSpan', span); } diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 6daa932e9b8d..34452bc336cd 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -20,8 +20,9 @@ export { captureEvent, captureMessage, configureScope, - getCurrentHub, + finishSpan, getHubFromCarrier, + getCurrentHub, Hub, Scope, setContext, @@ -30,6 +31,7 @@ export { setTag, setTags, setUser, + startSpan, Span, withScope, } from '@sentry/core'; diff --git a/packages/types/src/hub.ts b/packages/types/src/hub.ts index b873f38ebbdc..653b3497aa9c 100644 --- a/packages/types/src/hub.ts +++ b/packages/types/src/hub.ts @@ -191,5 +191,5 @@ export interface Hub { * * @param span `Span` instance that was created by {@link startSpan} */ - finishSpan(span: Span): string | undefined; + finishSpan(span?: Span): string | undefined; } From 4f7b6eb42824d915ce1c6750cef77d4bcc6d5cb5 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 24 Jul 2019 11:44:02 +0200 Subject: [PATCH 14/63] feat: Add more tests --- packages/hub/test/hub.test.ts | 325 +++++++++++++++++++-------------- packages/hub/test/span.test.ts | 55 ++++-- 2 files changed, 227 insertions(+), 153 deletions(-) diff --git a/packages/hub/test/hub.test.ts b/packages/hub/test/hub.test.ts index 5bb1945991ab..54bf6ac13ba5 100644 --- a/packages/hub/test/hub.test.ts +++ b/packages/hub/test/hub.test.ts @@ -32,33 +32,57 @@ describe('Hub', () => { expect(hub.isOlderThan(0)).toBeFalsy(); }); - test('pushScope', () => { - const localScope = new Scope(); - localScope.setExtra('a', 'b'); - const hub = new Hub(undefined, localScope); - hub.pushScope(); - expect(hub.getStack()).toHaveLength(2); - expect(hub.getStack()[1].scope).not.toBe(localScope); - expect(((hub.getStack()[1].scope as Scope) as any)._extra).toEqual({ a: 'b' }); - }); + describe('pushScope', () => { + test('simple', () => { + const localScope = new Scope(); + localScope.setExtra('a', 'b'); + const hub = new Hub(undefined, localScope); + hub.pushScope(); + expect(hub.getStack()).toHaveLength(2); + expect(hub.getStack()[1].scope).not.toBe(localScope); + expect(((hub.getStack()[1].scope as Scope) as any)._extra).toEqual({ a: 'b' }); + }); - test('pushScope inherit client', () => { - const testClient: any = { bla: 'a' }; - const hub = new Hub(testClient); - hub.pushScope(); - expect(hub.getStack()).toHaveLength(2); - expect(hub.getStack()[1].client).toBe(testClient); - }); + test('inherit client', () => { + const testClient: any = { bla: 'a' }; + const hub = new Hub(testClient); + hub.pushScope(); + expect(hub.getStack()).toHaveLength(2); + expect(hub.getStack()[1].client).toBe(testClient); + }); - test('pushScope bindClient', () => { - const testClient: any = { bla: 'a' }; - const hub = new Hub(testClient); - const ndClient: any = { foo: 'bar' }; - hub.pushScope(); - hub.bindClient(ndClient); - expect(hub.getStack()).toHaveLength(2); - expect(hub.getStack()[0].client).toBe(testClient); - expect(hub.getStack()[1].client).toBe(ndClient); + test('bindClient', () => { + const testClient: any = { bla: 'a' }; + const hub = new Hub(testClient); + const ndClient: any = { foo: 'bar' }; + hub.pushScope(); + hub.bindClient(ndClient); + expect(hub.getStack()).toHaveLength(2); + expect(hub.getStack()[0].client).toBe(testClient); + expect(hub.getStack()[1].client).toBe(ndClient); + }); + + test('inherit processors', () => { + expect.assertions(1); + const event: Event = { + extra: { b: 3 }, + }; + const localScope = new Scope(); + localScope.setExtra('a', 'b'); + const hub = new Hub({ a: 'b' } as any, localScope); + + localScope.addEventProcessor(async (processedEvent: Event) => { + processedEvent.dist = '1'; + return processedEvent; + }); + + hub.pushScope(); + const pushedScope = hub.getStackTop().scope; + + return pushedScope!.applyToEvent(event).then(final => { + expect(final!.dist).toEqual('1'); + }); + }); }); test('popScope', () => { @@ -69,23 +93,25 @@ describe('Hub', () => { expect(hub.getStack()).toHaveLength(1); }); - test('withScope', () => { - const hub = new Hub(); - hub.withScope(() => { - expect(hub.getStack()).toHaveLength(2); + describe('withScope', () => { + test('simple', () => { + const hub = new Hub(); + hub.withScope(() => { + expect(hub.getStack()).toHaveLength(2); + }); + expect(hub.getStack()).toHaveLength(1); }); - expect(hub.getStack()).toHaveLength(1); - }); - test('withScope bindClient', () => { - const hub = new Hub(); - const testClient: any = { bla: 'a' }; - hub.withScope(() => { - hub.bindClient(testClient); - expect(hub.getStack()).toHaveLength(2); - expect(hub.getStack()[1].client).toBe(testClient); + test('bindClient', () => { + const hub = new Hub(); + const testClient: any = { bla: 'a' }; + hub.withScope(() => { + hub.bindClient(testClient); + expect(hub.getStack()).toHaveLength(2); + expect(hub.getStack()[1].client).toBe(testClient); + }); + expect(hub.getStack()).toHaveLength(1); }); - expect(hub.getStack()).toHaveLength(1); }); test('getCurrentClient', () => { @@ -109,98 +135,103 @@ describe('Hub', () => { expect(hub.getStackTop().client).toEqual({ bla: 'a' }); }); - test('captureException', () => { - const hub = new Hub(); - const spy = jest.spyOn(hub as any, '_invokeClient'); - hub.captureException('a'); - expect(spy).toHaveBeenCalled(); - expect(spy.mock.calls[0][0]).toBe('captureException'); - expect(spy.mock.calls[0][1]).toBe('a'); - }); + describe('configureScope', () => { + test('no client, should not invoke configureScope', () => { + expect.assertions(0); + const hub = new Hub(); + hub.configureScope(_ => { + expect(true).toBeFalsy(); + }); + }); - test('captureMessage', () => { - const hub = new Hub(); - const spy = jest.spyOn(hub as any, '_invokeClient'); - hub.captureMessage('a'); - expect(spy).toHaveBeenCalled(); - expect(spy.mock.calls[0][0]).toBe('captureMessage'); - expect(spy.mock.calls[0][1]).toBe('a'); + test('no client, should not invoke configureScope', () => { + expect.assertions(1); + const localScope = new Scope(); + localScope.setExtra('a', 'b'); + const hub = new Hub({ a: 'b' } as any, localScope); + hub.configureScope(confScope => { + expect((confScope as any)._extra).toEqual({ a: 'b' }); + }); + }); }); - test('captureEvent', () => { - const event: Event = { - extra: { b: 3 }, - }; - const hub = new Hub(); - const spy = jest.spyOn(hub as any, '_invokeClient'); - hub.captureEvent(event); - expect(spy).toHaveBeenCalled(); - expect(spy.mock.calls[0][0]).toBe('captureEvent'); - expect(spy.mock.calls[0][1]).toBe(event); - }); + describe('captureException', () => { + test('simple', () => { + const hub = new Hub(); + const spy = jest.spyOn(hub as any, '_invokeClient'); + hub.captureException('a'); + expect(spy).toHaveBeenCalled(); + expect(spy.mock.calls[0][0]).toBe('captureException'); + expect(spy.mock.calls[0][1]).toBe('a'); + }); - test('configureScope', () => { - expect.assertions(0); - const hub = new Hub(); - hub.configureScope(_ => { - expect(true).toBeFalsy(); + test('should set event_id in hint', () => { + const hub = new Hub(); + const spy = jest.spyOn(hub as any, '_invokeClient'); + hub.captureException('a'); + expect(spy.mock.calls[0][2].event_id).toBeTruthy(); }); - }); - test('configureScope', () => { - expect.assertions(1); - const localScope = new Scope(); - localScope.setExtra('a', 'b'); - const hub = new Hub({ a: 'b' } as any, localScope); - hub.configureScope(confScope => { - expect((confScope as any)._extra).toEqual({ a: 'b' }); + test('should generate hint if not provided in the call', () => { + const hub = new Hub(); + const spy = jest.spyOn(hub as any, '_invokeClient'); + const ex = new Error('foo'); + hub.captureException(ex); + expect(spy.mock.calls[0][2].originalException).toBe(ex); + expect(spy.mock.calls[0][2].syntheticException).toBeInstanceOf(Error); + expect(spy.mock.calls[0][2].syntheticException.message).toBe('Sentry syntheticException'); }); }); - test('pushScope inherit processors', () => { - expect.assertions(1); - const event: Event = { - extra: { b: 3 }, - }; - const localScope = new Scope(); - localScope.setExtra('a', 'b'); - const hub = new Hub({ a: 'b' } as any, localScope); - - localScope.addEventProcessor(async (processedEvent: Event) => { - processedEvent.dist = '1'; - return processedEvent; + describe('captureMessage', () => { + test('simple', () => { + const hub = new Hub(); + const spy = jest.spyOn(hub as any, '_invokeClient'); + hub.captureMessage('a'); + expect(spy).toHaveBeenCalled(); + expect(spy.mock.calls[0][0]).toBe('captureMessage'); + expect(spy.mock.calls[0][1]).toBe('a'); }); - hub.pushScope(); - const pushedScope = hub.getStackTop().scope; - - return pushedScope!.applyToEvent(event).then(final => { - expect(final!.dist).toEqual('1'); + test('should set event_id in hint', () => { + const hub = new Hub(); + const spy = jest.spyOn(hub as any, '_invokeClient'); + hub.captureMessage('a'); + expect(spy.mock.calls[0][3].event_id).toBeTruthy(); }); - }); - test('captureException should set event_id in hint', () => { - const hub = new Hub(); - const spy = jest.spyOn(hub as any, '_invokeClient'); - hub.captureException('a'); - expect(spy.mock.calls[0][2].event_id).toBeTruthy(); + test('should generate hint if not provided in the call', () => { + const hub = new Hub(); + const spy = jest.spyOn(hub as any, '_invokeClient'); + hub.captureMessage('foo'); + expect(spy.mock.calls[0][3].originalException).toBe('foo'); + expect(spy.mock.calls[0][3].syntheticException).toBeInstanceOf(Error); + expect(spy.mock.calls[0][3].syntheticException.message).toBe('foo'); + }); }); - test('captureMessage should set event_id in hint', () => { - const hub = new Hub(); - const spy = jest.spyOn(hub as any, '_invokeClient'); - hub.captureMessage('a'); - expect(spy.mock.calls[0][3].event_id).toBeTruthy(); - }); + describe('captureEvent', () => { + test('simple', () => { + const event: Event = { + extra: { b: 3 }, + }; + const hub = new Hub(); + const spy = jest.spyOn(hub as any, '_invokeClient'); + hub.captureEvent(event); + expect(spy).toHaveBeenCalled(); + expect(spy.mock.calls[0][0]).toBe('captureEvent'); + expect(spy.mock.calls[0][1]).toBe(event); + }); - test('captureEvent should set event_id in hint', () => { - const event: Event = { - extra: { b: 3 }, - }; - const hub = new Hub(); - const spy = jest.spyOn(hub as any, '_invokeClient'); - hub.captureEvent(event); - expect(spy.mock.calls[0][2].event_id).toBeTruthy(); + test('should set event_id in hint', () => { + const event: Event = { + extra: { b: 3 }, + }; + const hub = new Hub(); + const spy = jest.spyOn(hub as any, '_invokeClient'); + hub.captureEvent(event); + expect(spy.mock.calls[0][2].event_id).toBeTruthy(); + }); }); test('lastEventId should be the same as last created', () => { @@ -212,25 +243,6 @@ describe('Hub', () => { expect(eventId).toBe(hub.lastEventId()); }); - test('captureException should generate hint if not provided in the call', () => { - const hub = new Hub(); - const spy = jest.spyOn(hub as any, '_invokeClient'); - const ex = new Error('foo'); - hub.captureException(ex); - expect(spy.mock.calls[0][2].originalException).toBe(ex); - expect(spy.mock.calls[0][2].syntheticException).toBeInstanceOf(Error); - expect(spy.mock.calls[0][2].syntheticException.message).toBe('Sentry syntheticException'); - }); - - test('captureMessage should generate hint if not provided in the call', () => { - const hub = new Hub(); - const spy = jest.spyOn(hub as any, '_invokeClient'); - hub.captureMessage('foo'); - expect(spy.mock.calls[0][3].originalException).toBe('foo'); - expect(spy.mock.calls[0][3].syntheticException).toBeInstanceOf(Error); - expect(spy.mock.calls[0][3].syntheticException.message).toBe('foo'); - }); - test('run', () => { const currentHub = getCurrentHub(); const myScope = new Scope(); @@ -269,4 +281,49 @@ describe('Hub', () => { }); }); }); + + describe('spans', () => { + describe('start', () => { + test('simple', () => { + const hub = new Hub(clientFn); + const span = hub.startSpan() as any; + expect(span._spanId).toBeTruthy(); + }); + + test('bindOnScope', () => { + const myScope = new Scope(); + const hub = new Hub(clientFn, myScope); + const span = hub.startSpan({}, true) as any; + expect((myScope as any)._span).toBe(span); + }); + }); + + describe('finish', () => { + test('simple', () => { + const hub = new Hub(clientFn); + const span = hub.startSpan() as any; + expect(span.timestamp).toBeUndefined(); + expect(hub.finishSpan(span)).toBeUndefined(); + expect(span.timestamp).toBeGreaterThan(1); + }); + + test('finish a scope span without transaction', () => { + const myScope = new Scope(); + const hub = new Hub(clientFn, myScope); + const spy = jest.spyOn(hub as any, 'captureEvent'); + const span = hub.startSpan({}, true) as any; + expect(hub.finishSpan(span)).toBeUndefined(); + expect(spy).not.toHaveBeenCalled(); + }); + + test('finish a scope span with transaction', () => { + const myScope = new Scope(); + const hub = new Hub(clientFn, myScope); + const spy = jest.spyOn(hub as any, 'captureEvent'); + const span = hub.startSpan({ transaction: 'test' }, true) as any; + expect(hub.finishSpan(span)).toBeDefined(); + expect(spy).toHaveBeenCalled(); + }); + }); + }); }); diff --git a/packages/hub/test/span.test.ts b/packages/hub/test/span.test.ts index e5cf733440b4..97029087579e 100644 --- a/packages/hub/test/span.test.ts +++ b/packages/hub/test/span.test.ts @@ -1,8 +1,23 @@ import { Span, TRACEPARENT_REGEXP } from '../src'; describe('Span', () => { - test('toTraceparent', () => { - expect(new Span().toTraceparent()).toMatch(TRACEPARENT_REGEXP); + describe('newSpan', () => { + test('simple', () => { + const span = new Span({ sampled: true }); + const span2 = span.newSpan(); + expect((span2 as any)._parentSpanId).toBe((span as any)._spanId); + expect((span2 as any)._traceId).toBe((span as any)._traceId); + expect((span2 as any).sampled).toBe((span as any).sampled); + }); + }); + + describe('toTraceparent', () => { + test('simple', () => { + expect(new Span().toTraceparent()).toMatch(TRACEPARENT_REGEXP); + }); + test('with sample', () => { + expect(new Span({ sampled: true }).toTraceparent()).toMatch(TRACEPARENT_REGEXP); + }); }); describe('fromTraceparent', () => { @@ -35,26 +50,28 @@ describe('Span', () => { expect(from2._spanId).toHaveLength(16); expect(from2.sampled).toBeTruthy(); }); - }); - test('fromTraceparent - invalid', () => { - expect(Span.fromTraceparent('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bbbbbbbbbbbbbbbb-x')).toBeUndefined(); + test('invalid', () => { + expect(Span.fromTraceparent('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bbbbbbbbbbbbbbbb-x')).toBeUndefined(); + }); }); - test('toJSON', () => { - const span = JSON.parse( - JSON.stringify(new Span({ traceId: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', spanId: 'bbbbbbbbbbbbbbbb' })), - ); - expect(span).toHaveProperty('span_id', 'bbbbbbbbbbbbbbbb'); - expect(span).toHaveProperty('trace_id', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); - }); + describe('toJSON', () => { + test('simple', () => { + const span = JSON.parse( + JSON.stringify(new Span({ traceId: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', spanId: 'bbbbbbbbbbbbbbbb' })), + ); + expect(span).toHaveProperty('span_id', 'bbbbbbbbbbbbbbbb'); + expect(span).toHaveProperty('trace_id', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); + }); - test('toJSON with parent', () => { - const spanA = new Span({ traceId: 'a', spanId: 'b' }) as any; - const spanB = new Span({ traceId: 'c', spanId: 'd', sampled: false, parentSpanId: spanA._spanId }); - const serialized = JSON.parse(JSON.stringify(spanB)); - expect(serialized).toHaveProperty('parent_span_id', 'b'); - expect(serialized).toHaveProperty('span_id', 'd'); - expect(serialized).toHaveProperty('trace_id', 'c'); + test('with parent', () => { + const spanA = new Span({ traceId: 'a', spanId: 'b' }) as any; + const spanB = new Span({ traceId: 'c', spanId: 'd', sampled: false, parentSpanId: spanA._spanId }); + const serialized = JSON.parse(JSON.stringify(spanB)); + expect(serialized).toHaveProperty('parent_span_id', 'b'); + expect(serialized).toHaveProperty('span_id', 'd'); + expect(serialized).toHaveProperty('trace_id', 'c'); + }); }); }); From 307dd0f71377cc874386e3d834aed841b8129933 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 24 Jul 2019 11:48:05 +0200 Subject: [PATCH 15/63] fix: Test --- packages/core/test/lib/api.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/test/lib/api.test.ts b/packages/core/test/lib/api.test.ts index abe80de82cf4..2bc914cc720a 100644 --- a/packages/core/test/lib/api.test.ts +++ b/packages/core/test/lib/api.test.ts @@ -16,14 +16,14 @@ describe('API', () => { expect(new API(dsnPublic).getRequestHeaders('a', '1.0')).toMatchObject({ 'Content-Type': 'application/json', 'X-Sentry-Auth': expect.stringMatching( - /^Sentry sentry_version=\d, sentry_timestamp=\d+, sentry_client=a\/1\.0, sentry_key=abc$/, + /^Sentry sentry_version=\d, sentry_timestamp=\d+\.\d+, sentry_client=a\/1\.0, sentry_key=abc$/, ), }); expect(new API(legacyDsn).getRequestHeaders('a', '1.0')).toMatchObject({ 'Content-Type': 'application/json', 'X-Sentry-Auth': expect.stringMatching( - /^Sentry sentry_version=\d, sentry_timestamp=\d+, sentry_client=a\/1\.0, sentry_key=abc, sentry_secret=123$/, + /^Sentry sentry_version=\d, sentry_timestamp=\d+\.\d+, sentry_client=a\/1\.0, sentry_key=abc, sentry_secret=123$/, ), }); }); From 4b35daf4383f8609c9d881bde50c8ccdfa81863f Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 24 Jul 2019 14:14:19 +0200 Subject: [PATCH 16/63] meta: beta.3 --- packages/core/src/api.ts | 2 +- packages/hub/src/hub.ts | 1 + packages/minimal/src/index.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/core/src/api.ts b/packages/core/src/api.ts index b6a8c09bb500..2867de307c7e 100644 --- a/packages/core/src/api.ts +++ b/packages/core/src/api.ts @@ -54,7 +54,7 @@ export class API { public getRequestHeaders(clientName: string, clientVersion: string): { [key: string]: string } { const dsn = this._dsnObject; const header = [`Sentry sentry_version=${SENTRY_API_VERSION}`]; - header.push(`sentry_timestamp=${timestampWithMs()}`); + header.push(`sentry_timestamp=${timestampWithMs()}`); // TODO: This can be removed header.push(`sentry_client=${clientName}/${clientVersion}`); header.push(`sentry_key=${dsn.user}`); if (dsn.pass) { diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index f95840b506bb..be36515bd93f 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -433,6 +433,7 @@ export class Hub implements HubInterface { } if (passedSpan === undefined) { + logger.warn('There was no Span on the Scope and none was passed, do nothing.'); // We will do nothing since nothing was passed and there is no Span on the scope. return undefined; } diff --git a/packages/minimal/src/index.ts b/packages/minimal/src/index.ts index 5b47d86003eb..cdc199a93a4b 100644 --- a/packages/minimal/src/index.ts +++ b/packages/minimal/src/index.ts @@ -190,5 +190,5 @@ export function startSpan(spanContext?: SpanContext, bindOnScope?: boolean): Spa * @param span `Span` instance that was created by {@link startSpan} */ export function finishSpan(span?: Span): string | undefined { - return callOnHub('startSpan', span); + return callOnHub('finishSpan', span); } From 422efcd357ef0440311f90f692c6e4dae5dead1f Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 24 Jul 2019 14:59:46 +0200 Subject: [PATCH 17/63] meta: beta.4 --- packages/hub/src/hub.ts | 4 ++-- packages/hub/test/hub.test.ts | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index be36515bd93f..b4664c909d82 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -452,11 +452,11 @@ export class Hub implements HubInterface { // TODO: if sampled do what? - const finishedSpans = passedSpan.finishedSpans.filter(s => s !== span); + const finishedSpans = passedSpan.finishedSpans.filter(s => s !== passedSpan); const eventId = this.captureEvent({ contexts: { trace: passedSpan.getTraceContext() }, - spans: finishedSpans, + spans: finishedSpans.length > 0 ? finishedSpans : undefined, start_timestamp: passedSpan.startTimestamp, timestamp: passedSpan.timestamp, transaction: passedSpan.transaction, diff --git a/packages/hub/test/hub.test.ts b/packages/hub/test/hub.test.ts index 54bf6ac13ba5..15d9912f2a8e 100644 --- a/packages/hub/test/hub.test.ts +++ b/packages/hub/test/hub.test.ts @@ -323,6 +323,18 @@ describe('Hub', () => { const span = hub.startSpan({ transaction: 'test' }, true) as any; expect(hub.finishSpan(span)).toBeDefined(); expect(spy).toHaveBeenCalled(); + expect(spy.mock.calls[0][0].spans).toBeUndefined(); + }); + + test('finish a scope span with transaction + child span', () => { + const myScope = new Scope(); + const hub = new Hub(clientFn, myScope); + const spy = jest.spyOn(hub as any, 'captureEvent'); + const span = hub.startSpan({ transaction: 'test' }, true) as any; + hub.finishSpan(hub.startSpan()); + expect(hub.finishSpan(span)).toBeDefined(); + expect(spy).toHaveBeenCalled(); + expect(spy.mock.calls[0][0].spans).toHaveLength(1); }); }); }); From 0a83eae5a8a664d2de539f56f3240adb2911087f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Tue, 13 Aug 2019 13:59:07 +0200 Subject: [PATCH 18/63] Next iteration of span API --- packages/hub/src/hub.ts | 65 ++------------------------------- packages/hub/src/span.ts | 37 ++++++++++++++++++- packages/hub/test/hub.test.ts | 51 ++++---------------------- packages/hub/test/scope.test.ts | 20 ++++++++-- packages/hub/test/span.test.ts | 51 +++++++++++++++++++++++++- 5 files changed, 113 insertions(+), 111 deletions(-) diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index b4664c909d82..5bfe87dced33 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -397,75 +397,18 @@ export class Hub implements HubInterface { /** * @inheritDoc */ - public startSpan(spanContext?: SpanContext, bindOnScope: boolean = false): Span { + public startSpan(spanContext?: SpanContext): Span { const top = this.getStackTop(); - const simpleNewSpan = new Span(spanContext); - if (top.scope && top.client) { - if (bindOnScope) { - top.scope.setSpan(simpleNewSpan); - return simpleNewSpan; - } + if (top.scope) { const span = top.scope.getSpan(); + if (span) { return span.newSpan(spanContext); } } - return simpleNewSpan; - } - - /** - * @inheritDoc - */ - public finishSpan(span?: Span): string | undefined { - const top = this.getStackTop(); - let passedSpan = span; - - // If the passed span is undefined we try to get the span from the scope and finish it. - if (passedSpan === undefined) { - if (top.scope && top.client) { - const scopeSpan = top.scope.getSpan(); - if (scopeSpan) { - passedSpan = scopeSpan; - } - } - } - - if (passedSpan === undefined) { - logger.warn('There was no Span on the Scope and none was passed, do nothing.'); - // We will do nothing since nothing was passed and there is no Span on the scope. - return undefined; - } - - if (!passedSpan.timestamp) { - passedSpan.finish(); - } - - if (!passedSpan.transaction) { - return undefined; - } - - if (!top.client) { - return undefined; - } - - // TODO: if sampled do what? - - const finishedSpans = passedSpan.finishedSpans.filter(s => s !== passedSpan); - - const eventId = this.captureEvent({ - contexts: { trace: passedSpan.getTraceContext() }, - spans: finishedSpans.length > 0 ? finishedSpans : undefined, - start_timestamp: passedSpan.startTimestamp, - timestamp: passedSpan.timestamp, - transaction: passedSpan.transaction, - type: 'transaction', - }); - - // After sending we reset the finishedSpans array - passedSpan.finishedSpans = []; - return eventId; + return new Span(spanContext); } } diff --git a/packages/hub/src/span.ts b/packages/hub/src/span.ts index ddec1def03a0..72ecd1192e2b 100644 --- a/packages/hub/src/span.ts +++ b/packages/hub/src/span.ts @@ -1,5 +1,6 @@ import { Span as SpanInterface, SpanContext } from '@sentry/types'; import { timestampWithMs, uuid4 } from '@sentry/utils'; +import { getCurrentHub, Hub } from './hub'; export const TRACEPARENT_REGEXP = /^[ \t]*([0-9a-f]{32})?-?([0-9a-f]{16})?-?([01])?[ \t]*$/; @@ -7,6 +8,11 @@ export const TRACEPARENT_REGEXP = /^[ \t]*([0-9a-f]{32})?-?([0-9a-f]{16})?-?([01 * Span contains all data about a span */ export class Span implements SpanInterface, SpanContext { + /** + * @inheritDoc + */ + private readonly _hub: Hub = getCurrentHub(); + /** * @inheritDoc */ @@ -67,7 +73,11 @@ export class Span implements SpanInterface, SpanContext { */ public finishedSpans: Span[] = []; - public constructor(spanContext?: SpanContext) { + public constructor(spanContext?: SpanContext, hub?: Hub) { + if (hub instanceof Hub) { + this._hub = hub; + } + if (!spanContext) { return this; } @@ -147,9 +157,32 @@ export class Span implements SpanInterface, SpanContext { /** * Sets the finish timestamp on the current span */ - public finish(): void { + public finish(): string | undefined { + // Don't allow for finishing more than once + if (typeof this.timestamp === 'number') { + return undefined; + } + this.timestamp = timestampWithMs(); this.finishedSpans.push(this); + + // Don't send non-transaction spans + if (typeof this.transaction !== 'string') { + return undefined; + } + + // TODO: if sampled do what? + const finishedSpans = this.finishedSpans.filter(s => s !== this); + this.finishedSpans = []; + + return this._hub.captureEvent({ + contexts: { trace: this.getTraceContext() }, + spans: finishedSpans.length > 0 ? finishedSpans : undefined, + start_timestamp: this.startTimestamp, + timestamp: this.timestamp, + transaction: this.transaction, + type: 'transaction', + }); } /** diff --git a/packages/hub/test/hub.test.ts b/packages/hub/test/hub.test.ts index 15d9912f2a8e..9f83885f13ed 100644 --- a/packages/hub/test/hub.test.ts +++ b/packages/hub/test/hub.test.ts @@ -290,51 +290,16 @@ describe('Hub', () => { expect(span._spanId).toBeTruthy(); }); - test('bindOnScope', () => { + test('inherits from parent span', () => { const myScope = new Scope(); const hub = new Hub(clientFn, myScope); - const span = hub.startSpan({}, true) as any; - expect((myScope as any)._span).toBe(span); - }); - }); - - describe('finish', () => { - test('simple', () => { - const hub = new Hub(clientFn); - const span = hub.startSpan() as any; - expect(span.timestamp).toBeUndefined(); - expect(hub.finishSpan(span)).toBeUndefined(); - expect(span.timestamp).toBeGreaterThan(1); - }); - - test('finish a scope span without transaction', () => { - const myScope = new Scope(); - const hub = new Hub(clientFn, myScope); - const spy = jest.spyOn(hub as any, 'captureEvent'); - const span = hub.startSpan({}, true) as any; - expect(hub.finishSpan(span)).toBeUndefined(); - expect(spy).not.toHaveBeenCalled(); - }); - - test('finish a scope span with transaction', () => { - const myScope = new Scope(); - const hub = new Hub(clientFn, myScope); - const spy = jest.spyOn(hub as any, 'captureEvent'); - const span = hub.startSpan({ transaction: 'test' }, true) as any; - expect(hub.finishSpan(span)).toBeDefined(); - expect(spy).toHaveBeenCalled(); - expect(spy.mock.calls[0][0].spans).toBeUndefined(); - }); - - test('finish a scope span with transaction + child span', () => { - const myScope = new Scope(); - const hub = new Hub(clientFn, myScope); - const spy = jest.spyOn(hub as any, 'captureEvent'); - const span = hub.startSpan({ transaction: 'test' }, true) as any; - hub.finishSpan(hub.startSpan()); - expect(hub.finishSpan(span)).toBeDefined(); - expect(spy).toHaveBeenCalled(); - expect(spy.mock.calls[0][0].spans).toHaveLength(1); + const parentSpan = hub.startSpan({}) as any; + expect(parentSpan._parentId).toBeFalsy(); + hub.configureScope(scope => { + scope.setSpan(parentSpan); + }); + const span = hub.startSpan({}) as any; + expect(span._parentSpanId).toBeTruthy(); }); }); }); diff --git a/packages/hub/test/scope.test.ts b/packages/hub/test/scope.test.ts index 25ac147d6419..5befadbefc39 100644 --- a/packages/hub/test/scope.test.ts +++ b/packages/hub/test/scope.test.ts @@ -1,7 +1,7 @@ import { Event, EventHint, Severity } from '@sentry/types'; import { getGlobalObject } from '@sentry/utils'; -import { addGlobalEventProcessor, Scope } from '../src'; +import { addGlobalEventProcessor, Scope, Span } from '../src'; describe('Scope', () => { afterEach(() => { @@ -73,9 +73,6 @@ describe('Scope', () => { scope.addBreadcrumb({ message: 'test' }, 100); expect((scope as any)._breadcrumbs[0]).toHaveProperty('message', 'test'); }); - }); - - describe('level', () => { test('set', () => { const scope = new Scope(); scope.setLevel(Severity.Critical); @@ -111,6 +108,21 @@ describe('Scope', () => { }); }); + describe('span', () => { + test('set', () => { + const scope = new Scope(); + const span = new Span({}); + scope.setSpan(span); + expect((scope as any)._span).toEqual(span); + }); + test('unset', () => { + const scope = new Scope(); + scope.setSpan(new Span({})); + scope.setSpan(); + expect((scope as any)._span).toEqual(undefined); + }); + }); + test('chaining', () => { const scope = new Scope(); scope.setLevel(Severity.Critical).setUser({ id: '1' }); diff --git a/packages/hub/test/span.test.ts b/packages/hub/test/span.test.ts index 97029087579e..3fc6ff679055 100644 --- a/packages/hub/test/span.test.ts +++ b/packages/hub/test/span.test.ts @@ -1,6 +1,14 @@ -import { Span, TRACEPARENT_REGEXP } from '../src'; +import { Span, TRACEPARENT_REGEXP, Hub, Scope } from '../src'; describe('Span', () => { + let hub: Hub; + + beforeEach(() => { + const clientFn: any = jest.fn(); + const myScope = new Scope(); + hub = new Hub(clientFn, myScope); + }); + describe('newSpan', () => { test('simple', () => { const span = new Span({ sampled: true }); @@ -9,6 +17,13 @@ describe('Span', () => { expect((span2 as any)._traceId).toBe((span as any)._traceId); expect((span2 as any).sampled).toBe((span as any).sampled); }); + + test.only('gets currentHub', () => { + const span = new Span({}); + const span2 = span.newSpan(); + expect((span as any)._hub).toBeInstanceOf(Hub); + expect((span2 as any)._hub).toBeInstanceOf(Hub); + }); }); describe('toTraceparent', () => { @@ -74,4 +89,38 @@ describe('Span', () => { expect(serialized).toHaveProperty('trace_id', 'c'); }); }); + + describe('finish', () => { + test('simple', () => { + const span = new Span({}); + expect(span.timestamp).toBeUndefined(); + span.finish(); + expect(span.timestamp).toBeGreaterThan(1); + }); + + test('finish a scope span without transaction', () => { + const spy = jest.spyOn(hub as any, 'captureEvent'); + const span = new Span({}, hub); + span.finish(); + expect(spy).not.toHaveBeenCalled(); + }); + + test('finish a scope span with transaction', () => { + const spy = jest.spyOn(hub as any, 'captureEvent') as any; + const span = new Span({ transaction: 'test' }, hub); + span.finish(); + expect(spy).toHaveBeenCalled(); + expect(spy.mock.calls[0][0].spans).toBeUndefined(); + }); + + test('finish a scope span with transaction + child span', () => { + const spy = jest.spyOn(hub as any, 'captureEvent') as any; + const parentSpan = new Span({ transaction: 'test' }, hub); + const childSpan = parentSpan.newSpan(); + childSpan.finish(); + parentSpan.finish(); + expect(spy).toHaveBeenCalled(); + expect(spy.mock.calls[0][0].spans).toHaveLength(1); + }); + }); }); From 2e993b331c0614b14864f53a8d41584eed4b5b22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Wed, 14 Aug 2019 11:39:33 +0200 Subject: [PATCH 19/63] Add status to transactions --- packages/hub/src/span.ts | 63 +++++++++++++++++++++++-- packages/hub/test/span.test.ts | 86 +++++++++++++++++++++++++++++++++- packages/types/src/hub.ts | 9 ---- packages/types/src/span.ts | 4 ++ 4 files changed, 149 insertions(+), 13 deletions(-) diff --git a/packages/hub/src/span.ts b/packages/hub/src/span.ts index 72ecd1192e2b..6a5d18408a85 100644 --- a/packages/hub/src/span.ts +++ b/packages/hub/src/span.ts @@ -1,5 +1,6 @@ import { Span as SpanInterface, SpanContext } from '@sentry/types'; import { timestampWithMs, uuid4 } from '@sentry/utils'; + import { getCurrentHub, Hub } from './hub'; export const TRACEPARENT_REGEXP = /^[ \t]*([0-9a-f]{32})?-?([0-9a-f]{16})?-?([01])?[ \t]*$/; @@ -61,12 +62,12 @@ export class Span implements SpanInterface, SpanContext { /** * @inheritDoc */ - public tags?: { [key: string]: string }; + public tags: { [key: string]: string } = {}; /** * @inheritDoc */ - public data?: { [key: string]: any }; + public data: { [key: string]: any } = {}; /** * List of spans that were finalized @@ -154,6 +155,55 @@ export class Span implements SpanInterface, SpanContext { return undefined; } + /** + * Sets the tag attribute on the current span + * @param key Tag key + * @param value Tag value + */ + public setTag(key: string, value: string): this { + this.tags = { ...this.tags, [key]: value }; + return this; + } + + /** + * Sets the data attribute on the current span + * @param key Data key + * @param value Data value + */ + public setData(key: string, value: any): this { + this.data = { ...this.data, [key]: value }; + return this; + } + + /** + * Sets the data attribute on the current span + * @param key Data key + * @param value Data value + */ + public setFailure(): this { + this.setTag('status', 'failure'); + return this; + } + + /** + * Sets the data attribute on the current span + * @param key Data key + * @param value Data value + */ + public setSuccess(): this { + this.setTag('status', 'success'); + return this; + } + + /** + * Sets the data attribute on the current span + * @param key Data key + * @param value Data value + */ + public isSuccess(): boolean { + return this.tags.status !== 'failure'; + } + /** * Sets the finish timestamp on the current span */ @@ -200,7 +250,7 @@ export class Span implements SpanInterface, SpanContext { * @inheritDoc */ public getTraceContext(): object { - return { + const context = { data: this.data, description: this.description, op: this.op, @@ -209,6 +259,13 @@ export class Span implements SpanInterface, SpanContext { tags: this.tags, trace_id: this._traceId, }; + + if (this.tags.status) { + // TODO: Fixme, just use better typings + (context as any).status = this.tags.status; + } + + return context; } /** diff --git a/packages/hub/test/span.test.ts b/packages/hub/test/span.test.ts index 3fc6ff679055..5a7df8f10b62 100644 --- a/packages/hub/test/span.test.ts +++ b/packages/hub/test/span.test.ts @@ -18,7 +18,69 @@ describe('Span', () => { expect((span2 as any).sampled).toBe((span as any).sampled); }); - test.only('gets currentHub', () => { + test('gets currentHub', () => { + const span = new Span({}); + const span2 = span.newSpan(); + expect((span as any)._hub).toBeInstanceOf(Hub); + expect((span2 as any)._hub).toBeInstanceOf(Hub); + }); + }); + + describe('setters', () => { + test('setTag', () => { + const span = new Span({}); + expect(span.tags.foo).toBeUndefined(); + span.setTag('foo', 'bar'); + expect(span.tags.foo).toBe('bar'); + span.setTag('foo', 'baz'); + expect(span.tags.foo).toBe('baz'); + }); + + test('setData', () => { + const span = new Span({}); + expect(span.data.foo).toBeUndefined(); + span.setData('foo', null); + expect(span.data.foo).toBe(null); + span.setData('foo', 2); + expect(span.data.foo).toBe(2); + span.setData('foo', true); + expect(span.data.foo).toBe(true); + }); + }); + + describe('status', () => { + test('setSuccess', () => { + const span = new Span({}); + span.setSuccess(); + expect(span.tags.status).toBe('success'); + }); + + test('setFailure', () => { + const span = new Span({}); + span.setFailure(); + expect(span.tags.status).toBe('failure'); + }); + + test('isSuccess', () => { + const span = new Span({}); + expect(span.isSuccess()).toBe(true); + span.setFailure(); + expect(span.isSuccess()).toBe(false); + span.setSuccess(); + expect(span.isSuccess()).toBe(true); + }); + }); + + describe('newSpan', () => { + test('simple', () => { + const span = new Span({ sampled: true }); + const span2 = span.newSpan(); + expect((span2 as any)._parentSpanId).toBe((span as any)._spanId); + expect((span2 as any)._traceId).toBe((span as any)._traceId); + expect((span2 as any).sampled).toBe((span as any).sampled); + }); + + test('gets currentHub', () => { const span = new Span({}); const span2 = span.newSpan(); expect((span as any)._hub).toBeInstanceOf(Hub); @@ -123,4 +185,26 @@ describe('Span', () => { expect(spy.mock.calls[0][0].spans).toHaveLength(1); }); }); + + describe('getTraceContext', () => { + test('should have status attribute undefined if no status tag is available', () => { + const span = new Span({}); + const context = span.getTraceContext(); + expect((context as any).status).toBeUndefined(); + }); + + test('should have success status extracted from tags', () => { + const span = new Span({}); + span.setSuccess(); + const context = span.getTraceContext(); + expect((context as any).status).toBe('success'); + }); + + test('should have failure status extracted from tags', () => { + const span = new Span({}); + span.setFailure(); + const context = span.getTraceContext(); + expect((context as any).status).toBe('failure'); + }); + }); }); diff --git a/packages/types/src/hub.ts b/packages/types/src/hub.ts index 653b3497aa9c..a91fef6dec9f 100644 --- a/packages/types/src/hub.ts +++ b/packages/types/src/hub.ts @@ -183,13 +183,4 @@ export interface Hub { * @param bindOnScope Determines if the started span will be set on the Scope */ startSpan(spanContext?: SpanContext, bindOnScope?: boolean): Span; - - /** - * This finishes the passed `Span`. If the `Span` has the property `transaction` set and it's bound on the - * current Scope, an `transaction` Event will be sent to Sentry containing all finished Spans inbetween. - * Returns either an `event.id` or `undefined` in case event wasn't sent. - * - * @param span `Span` instance that was created by {@link startSpan} - */ - finishSpan(span?: Span): string | undefined; } diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index ec08adc4a6f8..74e55e238e32 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -18,6 +18,10 @@ export interface SpanContext { * Operation of the Span. */ op?: string; + /** + * Completion status of the Span. + */ + status?: boolean; /** * Parent Span ID */ From 206c46bca5e208ca5f94cd0557682e2d7cd3b47a Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Tue, 20 Aug 2019 14:16:23 +0200 Subject: [PATCH 20/63] fix: Span changes --- packages/hub/src/hub.ts | 2 +- packages/hub/src/span.ts | 4 ++-- packages/hub/test/span.test.ts | 10 +++++----- packages/minimal/src/index.ts | 19 ++----------------- 4 files changed, 10 insertions(+), 25 deletions(-) diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index 5bfe87dced33..ddfa41133f74 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -404,7 +404,7 @@ export class Hub implements HubInterface { const span = top.scope.getSpan(); if (span) { - return span.newSpan(spanContext); + return span.makeChild(spanContext); } } diff --git a/packages/hub/src/span.ts b/packages/hub/src/span.ts index 6a5d18408a85..32a999248bbe 100644 --- a/packages/hub/src/span.ts +++ b/packages/hub/src/span.ts @@ -10,7 +10,7 @@ export const TRACEPARENT_REGEXP = /^[ \t]*([0-9a-f]{32})?-?([0-9a-f]{16})?-?([01 */ export class Span implements SpanInterface, SpanContext { /** - * @inheritDoc + * The reference to the current hub. */ private readonly _hub: Hub = getCurrentHub(); @@ -116,7 +116,7 @@ export class Span implements SpanInterface, SpanContext { * Creates a new `Span` while setting the current `Span.id` as `parentSpanId`. * Also the `sampled` decision will be inherited. */ - public newSpan(spanContext?: Pick>): Span { + public makeChild(spanContext?: Pick>): Span { const span = new Span({ ...spanContext, parentSpanId: this._spanId, diff --git a/packages/hub/test/span.test.ts b/packages/hub/test/span.test.ts index 5a7df8f10b62..baf1537e3dcc 100644 --- a/packages/hub/test/span.test.ts +++ b/packages/hub/test/span.test.ts @@ -12,7 +12,7 @@ describe('Span', () => { describe('newSpan', () => { test('simple', () => { const span = new Span({ sampled: true }); - const span2 = span.newSpan(); + const span2 = span.makeChild(); expect((span2 as any)._parentSpanId).toBe((span as any)._spanId); expect((span2 as any)._traceId).toBe((span as any)._traceId); expect((span2 as any).sampled).toBe((span as any).sampled); @@ -20,7 +20,7 @@ describe('Span', () => { test('gets currentHub', () => { const span = new Span({}); - const span2 = span.newSpan(); + const span2 = span.makeChild(); expect((span as any)._hub).toBeInstanceOf(Hub); expect((span2 as any)._hub).toBeInstanceOf(Hub); }); @@ -74,7 +74,7 @@ describe('Span', () => { describe('newSpan', () => { test('simple', () => { const span = new Span({ sampled: true }); - const span2 = span.newSpan(); + const span2 = span.makeChild(); expect((span2 as any)._parentSpanId).toBe((span as any)._spanId); expect((span2 as any)._traceId).toBe((span as any)._traceId); expect((span2 as any).sampled).toBe((span as any).sampled); @@ -82,7 +82,7 @@ describe('Span', () => { test('gets currentHub', () => { const span = new Span({}); - const span2 = span.newSpan(); + const span2 = span.makeChild(); expect((span as any)._hub).toBeInstanceOf(Hub); expect((span2 as any)._hub).toBeInstanceOf(Hub); }); @@ -178,7 +178,7 @@ describe('Span', () => { test('finish a scope span with transaction + child span', () => { const spy = jest.spyOn(hub as any, 'captureEvent') as any; const parentSpan = new Span({ transaction: 'test' }, hub); - const childSpan = parentSpan.newSpan(); + const childSpan = parentSpan.makeChild(); childSpan.finish(); parentSpan.finish(); expect(spy).toHaveBeenCalled(); diff --git a/packages/minimal/src/index.ts b/packages/minimal/src/index.ts index cdc199a93a4b..ebc465dbe97c 100644 --- a/packages/minimal/src/index.ts +++ b/packages/minimal/src/index.ts @@ -171,24 +171,9 @@ export function _callOnClient(method: string, ...args: any[]): void { /** * This functions starts a span. If just a `SpanContext` is passed and there is already a Span * on the Scope, the created Span will have a reference to the one on the Scope. - * If a Span is on the current Scope it is considered a `transaction`. - * When using the second parameter it will set the created Span on the Scope (replacing whats there). - * This can be used as a shortcut to not set it manually on the Scope. * * @param spanContext Properties with which the span should be created - * @param bindOnScope Determines if the started span will be set on the Scope */ -export function startSpan(spanContext?: SpanContext, bindOnScope?: boolean): Span { - return callOnHub('startSpan', spanContext, bindOnScope); -} - -/** - * This finishes the passed `Span`. If the `Span` has the property `transaction` set and it's bound on the - * current Scope, an `transaction` Event will be sent to Sentry containing all finished Spans inbetween. - * Returns either an `event.id` or `undefined` in case event wasn't sent. - * - * @param span `Span` instance that was created by {@link startSpan} - */ -export function finishSpan(span?: Span): string | undefined { - return callOnHub('finishSpan', span); +export function startSpan(spanContext?: SpanContext): Span { + return callOnHub('startSpan', spanContext); } From 1b9ebd9fa2c3dde3852bd6fc28b7d4378f5a9e08 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 21 Aug 2019 14:17:24 +0200 Subject: [PATCH 21/63] ref: naming --- packages/hub/src/hub.ts | 2 +- packages/hub/src/span.ts | 2 +- packages/hub/test/span.test.ts | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index ddfa41133f74..97865f6761c7 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -404,7 +404,7 @@ export class Hub implements HubInterface { const span = top.scope.getSpan(); if (span) { - return span.makeChild(spanContext); + return span.child(spanContext); } } diff --git a/packages/hub/src/span.ts b/packages/hub/src/span.ts index 32a999248bbe..602073ac2fe6 100644 --- a/packages/hub/src/span.ts +++ b/packages/hub/src/span.ts @@ -116,7 +116,7 @@ export class Span implements SpanInterface, SpanContext { * Creates a new `Span` while setting the current `Span.id` as `parentSpanId`. * Also the `sampled` decision will be inherited. */ - public makeChild(spanContext?: Pick>): Span { + public child(spanContext?: Pick>): Span { const span = new Span({ ...spanContext, parentSpanId: this._spanId, diff --git a/packages/hub/test/span.test.ts b/packages/hub/test/span.test.ts index baf1537e3dcc..a7cfafee9054 100644 --- a/packages/hub/test/span.test.ts +++ b/packages/hub/test/span.test.ts @@ -12,7 +12,7 @@ describe('Span', () => { describe('newSpan', () => { test('simple', () => { const span = new Span({ sampled: true }); - const span2 = span.makeChild(); + const span2 = span.child(); expect((span2 as any)._parentSpanId).toBe((span as any)._spanId); expect((span2 as any)._traceId).toBe((span as any)._traceId); expect((span2 as any).sampled).toBe((span as any).sampled); @@ -20,7 +20,7 @@ describe('Span', () => { test('gets currentHub', () => { const span = new Span({}); - const span2 = span.makeChild(); + const span2 = span.child(); expect((span as any)._hub).toBeInstanceOf(Hub); expect((span2 as any)._hub).toBeInstanceOf(Hub); }); @@ -74,7 +74,7 @@ describe('Span', () => { describe('newSpan', () => { test('simple', () => { const span = new Span({ sampled: true }); - const span2 = span.makeChild(); + const span2 = span.child(); expect((span2 as any)._parentSpanId).toBe((span as any)._spanId); expect((span2 as any)._traceId).toBe((span as any)._traceId); expect((span2 as any).sampled).toBe((span as any).sampled); @@ -82,7 +82,7 @@ describe('Span', () => { test('gets currentHub', () => { const span = new Span({}); - const span2 = span.makeChild(); + const span2 = span.child(); expect((span as any)._hub).toBeInstanceOf(Hub); expect((span2 as any)._hub).toBeInstanceOf(Hub); }); @@ -178,7 +178,7 @@ describe('Span', () => { test('finish a scope span with transaction + child span', () => { const spy = jest.spyOn(hub as any, 'captureEvent') as any; const parentSpan = new Span({ transaction: 'test' }, hub); - const childSpan = parentSpan.makeChild(); + const childSpan = parentSpan.child(); childSpan.finish(); parentSpan.finish(); expect(spy).toHaveBeenCalled(); From 1db7ac449787ccbe2bb3c0948fe40ef401be0978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Thu, 22 Aug 2019 13:01:29 +0200 Subject: [PATCH 22/63] fix: Remove finishSpan from core, node and browser exports --- packages/browser/src/index.ts | 1 - packages/core/src/index.ts | 1 - packages/node/src/index.ts | 1 - 3 files changed, 3 deletions(-) diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index db4904801795..4be86ae0067c 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -20,7 +20,6 @@ export { captureEvent, captureMessage, configureScope, - finishSpan, getHubFromCarrier, getCurrentHub, Hub, diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 37a44e134760..3a3508aa3b15 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -4,7 +4,6 @@ export { captureEvent, captureMessage, configureScope, - finishSpan, setContext, setExtra, setExtras, diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 34452bc336cd..e12402a23daf 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -20,7 +20,6 @@ export { captureEvent, captureMessage, configureScope, - finishSpan, getHubFromCarrier, getCurrentHub, Hub, From 679d2db11b858ccb9290ebb8b1bf53758c225669 Mon Sep 17 00:00:00 2001 From: HazA Date: Fri, 4 Oct 2019 19:31:02 +0200 Subject: [PATCH 23/63] fix: Linter for tests --- packages/hub/test/span.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hub/test/span.test.ts b/packages/hub/test/span.test.ts index a7cfafee9054..233766d7ebd9 100644 --- a/packages/hub/test/span.test.ts +++ b/packages/hub/test/span.test.ts @@ -1,4 +1,4 @@ -import { Span, TRACEPARENT_REGEXP, Hub, Scope } from '../src'; +import { Span, Hub, Scope, TRACEPARENT_REGEXP } from '../src'; describe('Span', () => { let hub: Hub; From 11e3f8b9e54ff03df4bedc60f66c871487d0b1e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Wed, 9 Oct 2019 12:49:42 +0200 Subject: [PATCH 24/63] fix: Add finish method to the Span interface --- packages/hub/test/span.test.ts | 2 +- packages/types/src/span.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/hub/test/span.test.ts b/packages/hub/test/span.test.ts index 233766d7ebd9..42d3c873133b 100644 --- a/packages/hub/test/span.test.ts +++ b/packages/hub/test/span.test.ts @@ -1,4 +1,4 @@ -import { Span, Hub, Scope, TRACEPARENT_REGEXP } from '../src'; +import { Hub, Scope, Span, TRACEPARENT_REGEXP } from '../src'; describe('Span', () => { let hub: Hub; diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index 74e55e238e32..6f4098aac418 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -1,5 +1,7 @@ /** Span holding trace_id, span_id */ export interface Span { + /** Sets the finish timestamp on the current span and sends it if it was a transaction */ + finish(): string | undefined; /** Return a traceparent compatible header string */ toTraceparent(): string; /** Convert the object to JSON for w. spans array info only */ From 3601e3d4c3393c25c3b970e12ca82e32dc1e2a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Wed, 23 Oct 2019 17:15:09 +0200 Subject: [PATCH 25/63] Bring APM implementation up to date with python --- packages/hub/src/hub.ts | 48 ++++++++++++++---- packages/hub/src/span.ts | 96 ++++++++++++++++++++++++++++++----- packages/types/src/hub.ts | 13 ++--- packages/types/src/options.ts | 7 +++ 4 files changed, 131 insertions(+), 33 deletions(-) diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index 97865f6761c7..737a26c8ac7c 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -35,6 +35,14 @@ declare module 'domain' { } } +/** + * Checks whether given value is instance of Span + * @param span value to check + */ +function isSpanInstance(span: unknown): span is Span { + return span instanceof Span; +} + /** * API compatibility version of this hub. * @@ -382,9 +390,9 @@ export class Hub implements HubInterface { * @inheritDoc */ public traceHeaders(): { [key: string]: string } { - const top = this.getStackTop(); - if (top.scope && top.client) { - const span = top.scope.getSpan(); + const scope = this.getScope(); + if (scope) { + const span = scope.getSpan(); if (span) { return { 'sentry-trace': span.toTraceparent(), @@ -397,18 +405,36 @@ export class Hub implements HubInterface { /** * @inheritDoc */ - public startSpan(spanContext?: SpanContext): Span { - const top = this.getStackTop(); + public startSpan(spanOrSpanContext?: Span | SpanContext): Span { + const scope = this.getScope(); + const client = this.getClient(); + let span; + + if (!isSpanInstance(spanOrSpanContext)) { + if (scope) { + const parentSpan = scope.getSpan(); + if (parentSpan) { + span = parentSpan.child(spanOrSpanContext); + } + } + } - if (top.scope) { - const span = top.scope.getSpan(); + if (!isSpanInstance(span)) { + span = new Span(spanOrSpanContext, this); + } - if (span) { - return span.child(spanContext); - } + if (span.sampled === undefined && span.transaction !== undefined) { + const sampleRate = (client && client.getOptions().tracesSampleRate) || 0; + span.sampled = Math.random() < sampleRate; + } + + if (span.sampled) { + const experimentsOptions = (client && client.getOptions()._experiments) || {}; + const maxSpans = experimentsOptions.maxSpans || 1000; + span.initFinishedSpans(maxSpans); } - return new Span(spanContext); + return span; } } diff --git a/packages/hub/src/span.ts b/packages/hub/src/span.ts index 602073ac2fe6..10dc7e4e0ad2 100644 --- a/packages/hub/src/span.ts +++ b/packages/hub/src/span.ts @@ -1,9 +1,51 @@ +// tslint:disable:max-classes-per-file + import { Span as SpanInterface, SpanContext } from '@sentry/types'; -import { timestampWithMs, uuid4 } from '@sentry/utils'; +import { logger, timestampWithMs, uuid4 } from '@sentry/utils'; import { getCurrentHub, Hub } from './hub'; -export const TRACEPARENT_REGEXP = /^[ \t]*([0-9a-f]{32})?-?([0-9a-f]{16})?-?([01])?[ \t]*$/; +export const TRACEPARENT_REGEXP = new RegExp( + '^[ \\t]*' + // whitespace + '([0-9a-f]{32})?' + // trace_id + '-?([0-9a-f]{16})?' + // span_id + '-?([01])?' + // sampled + '[ \\t]*$', // whitespace +); + +/** + * Keeps track of finished spans for a given transaction + */ +class SpanRecorder { + private readonly _maxlen: number; + private _openSpanCount: number = 0; + public finishedSpans: Span[] = []; + + public constructor(maxlen: number) { + this._maxlen = maxlen; + } + + /** + * This is just so that we don't run out of memory while recording a lot + * of spans. At some point we just stop and flush out the start of the + * trace tree (i.e.the first n spans with the smallest + * start_timestamp). + */ + public startSpan(span: Span): void { + this._openSpanCount += 1; + if (this._openSpanCount > this._maxlen) { + span.spanRecorder = undefined; + } + } + + /** + * Appends a span to finished spans table + * @param span Span to be added + */ + public finishSpan(span: Span): void { + this.finishedSpans.push(span); + } +} /** * Span contains all data about a span @@ -32,7 +74,7 @@ export class Span implements SpanInterface, SpanContext { /** * @inheritDoc */ - public readonly sampled?: boolean; + public sampled?: boolean; /** * Timestamp when the span was created. @@ -72,7 +114,7 @@ export class Span implements SpanInterface, SpanContext { /** * List of spans that were finalized */ - public finishedSpans: Span[] = []; + public spanRecorder?: SpanRecorder; public constructor(spanContext?: SpanContext, hub?: Hub) { if (hub instanceof Hub) { @@ -112,6 +154,17 @@ export class Span implements SpanInterface, SpanContext { } } + /** + * Attaches SpanRecorder to the span itself + * @param maxlen maximum number of spans that can be recorded + */ + public initFinishedSpans(maxlen: number): void { + if (!this.spanRecorder) { + this.spanRecorder = new SpanRecorder(maxlen); + } + this.spanRecorder.startSpan(this); + } + /** * Creates a new `Span` while setting the current `Span.id` as `parentSpanId`. * Also the `sampled` decision will be inherited. @@ -124,7 +177,7 @@ export class Span implements SpanInterface, SpanContext { traceId: this._traceId, }); - span.finishedSpans = this.finishedSpans; + span.spanRecorder = this.spanRecorder; return span; } @@ -208,26 +261,41 @@ export class Span implements SpanInterface, SpanContext { * Sets the finish timestamp on the current span */ public finish(): string | undefined { - // Don't allow for finishing more than once - if (typeof this.timestamp === 'number') { + // This transaction is already finished, so we should not flush it again. + if (this.timestamp !== undefined) { return undefined; } this.timestamp = timestampWithMs(); - this.finishedSpans.push(this); - // Don't send non-transaction spans - if (typeof this.transaction !== 'string') { + if (this.spanRecorder === undefined) { + return undefined; + } + + this.spanRecorder.finishSpan(this); + + if (this.transaction === undefined) { + // If this has no transaction set we assume there's a parent + // transaction for this span that would be flushed out eventually. + return undefined; + } + + if (this.sampled === undefined) { + // At this point a `sampled === undefined` should have already been + // resolved to a concrete decision. If `sampled` is `undefined`, it's + // likely that somebody used `Sentry.startSpan(...)` on a + // non-transaction span and later decided to make it a transaction. + logger.warn('Discarding transaction Span without sampling decision'); return undefined; } - // TODO: if sampled do what? - const finishedSpans = this.finishedSpans.filter(s => s !== this); - this.finishedSpans = []; + const finishedSpans = !this.spanRecorder ? [] : this.spanRecorder.finishedSpans.filter(s => s !== this); return this._hub.captureEvent({ + // TODO: Is this necessary? We already do store contextx in in applyToEvent, + // so maybe we can move `getTraceContext` call there as well? contexts: { trace: this.getTraceContext() }, - spans: finishedSpans.length > 0 ? finishedSpans : undefined, + spans: finishedSpans, start_timestamp: this.startTimestamp, timestamp: this.timestamp, transaction: this.transaction, diff --git a/packages/types/src/hub.ts b/packages/types/src/hub.ts index a91fef6dec9f..5ea91f88dbe9 100644 --- a/packages/types/src/hub.ts +++ b/packages/types/src/hub.ts @@ -173,14 +173,11 @@ export interface Hub { traceHeaders(): { [key: string]: string }; /** - * This functions starts a span. If just a `SpanContext` is passed and there is already a Span - * on the Scope, the created Span will have a reference to the one on the Scope. - * If a Span is on the current Scope it is considered a `transaction`. - * When using the second parameter it will set the created Span on the Scope (replacing whats there). - * This can be used as a shortcut to not set it manually on the Scope. + * This functions starts a span. If argument passed is of type `Span`, it'll run sampling on it if configured + * and attach a `SpanRecorder`. If it's of type `SpanContext` and there is already a `Span` on the Scope, + * the created Span will have a reference to it and become it's child. Otherwise it'll crete a new `Span`. * - * @param spanContext Properties with which the span should be created - * @param bindOnScope Determines if the started span will be set on the Scope + * @param span Already constructed span which should be started or properties with which the span should be created */ - startSpan(spanContext?: SpanContext, bindOnScope?: boolean): Span; + startSpan(span?: Span | SpanContext): Span; } diff --git a/packages/types/src/options.ts b/packages/types/src/options.ts index ac31e40f41cc..70cd5adb7d3f 100644 --- a/packages/types/src/options.ts +++ b/packages/types/src/options.ts @@ -78,6 +78,9 @@ export interface Options { /** A global sample rate to apply to all events (0 - 1). */ sampleRate?: number; + /** A global sample rate to apply to all transactions (0 - 1). */ + tracesSampleRate?: number; + /** Attaches stacktraces to pure capture message / log integrations */ attachStacktrace?: boolean; @@ -110,4 +113,8 @@ export interface Options { * @returns The breadcrumb that will be added | null. */ beforeBreadcrumb?(breadcrumb: Breadcrumb, hint?: BreadcrumbHint): Breadcrumb | null; + + _experiments?: { + [key: string]: any; + }; } From 8966bf7fecde4e0b2525aebc5bb3b3631ac4faa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Fri, 25 Oct 2019 18:32:10 +0200 Subject: [PATCH 26/63] feat: Instrument http integration to emit breadcrumbs and/or spans --- packages/integrations/src/index.ts | 1 + packages/node/src/integrations/http.ts | 247 ++++++++++++------------- 2 files changed, 123 insertions(+), 125 deletions(-) diff --git a/packages/integrations/src/index.ts b/packages/integrations/src/index.ts index 5640f1fbd6fe..8244114822c1 100644 --- a/packages/integrations/src/index.ts +++ b/packages/integrations/src/index.ts @@ -3,6 +3,7 @@ export { CaptureConsole } from './captureconsole'; export { Debug } from './debug'; export { Dedupe } from './dedupe'; export { Ember } from './ember'; +export { Express } from './express'; export { ExtraErrorData } from './extraerrordata'; export { ReportingObserver } from './reportingobserver'; export { RewriteFrames } from './rewriteframes'; diff --git a/packages/node/src/integrations/http.ts b/packages/node/src/integrations/http.ts index d166a3dc09a2..0b2b7f608d3e 100644 --- a/packages/node/src/integrations/http.ts +++ b/packages/node/src/integrations/http.ts @@ -1,18 +1,8 @@ -import { getCurrentHub } from '@sentry/core'; +import { getCurrentHub, Span } from '@sentry/core'; import { Integration } from '@sentry/types'; import { fill } from '@sentry/utils'; import * as http from 'http'; -import * as util from 'util'; - -let lastResponse: http.ServerResponse | undefined; - -/** - * Request interface which can carry around unified url - * independently of used framework - */ -interface SentryRequest extends http.IncomingMessage { - __ravenBreadcrumbUrl?: string; -} +import * as https from 'https'; /** http module integration */ export class Http implements Integration { @@ -25,19 +15,118 @@ export class Http implements Integration { */ public static id: string = 'Http'; + /** + * @inheritDoc + */ + private readonly _breadcrumbs: boolean; + + /** + * @inheritDoc + */ + private readonly _tracing: boolean; + + /** + * @inheritDoc + */ + public constructor(options: { breadcrumbs?: boolean; tracing?: boolean } = {}) { + this._breadcrumbs = typeof options.breadcrumbs === 'undefined' ? true : options.breadcrumbs; + this._tracing = typeof options.tracing === 'undefined' ? false : options.tracing; + } + /** * @inheritDoc */ public setupOnce(): void { - const nativeModule = require('module'); - fill(nativeModule, '_load', loadWrapper(nativeModule)); - // observation: when the https module does its own require('http'), it *does not* hit our hooked require to instrument http on the fly - // but if we've previously instrumented http, https *does* get our already-instrumented version - // this is because raven's transports are required before this instrumentation takes place, which loads https (and http) - // so module cache will have uninstrumented http; proactively loading it here ensures instrumented version is in module cache - // alternatively we could refactor to load our transports later, but this is easier and doesn't have much drawback - require('http'); + // No need to instrument if we don't want to track anything + if (!this._breadcrumbs && !this._tracing) { + return; + } + + const handlerWrapper = createHandlerWrapper(this._breadcrumbs, this._tracing); + + const httpModule = require('http'); + fill(httpModule, 'get', handlerWrapper); + fill(httpModule, 'request', handlerWrapper); + + const httpsModule = require('https'); + fill(httpsModule, 'get', handlerWrapper); + fill(httpsModule, 'request', handlerWrapper); + } +} + +/** + * Wrapper function for internal `request` and `get` calls within `http` and `https` modules + */ +function createHandlerWrapper( + breadcrumbsEnabled: boolean, + tracingEnabled: boolean, +): (originalHandler: () => http.ClientRequest) => (options: string | http.ClientRequestArgs) => http.ClientRequest { + return function handlerWrapper( + originalHandler: () => http.ClientRequest, + ): (options: string | http.ClientRequestArgs) => http.ClientRequest { + return function(this: typeof http | typeof https, options: string | http.ClientRequestArgs): http.ClientRequest { + const requestUrl = extractUrl(options); + + if (isSentryRequest(requestUrl)) { + return originalHandler.apply(this, arguments); + } + + let span: Span; + if (tracingEnabled) { + span = getCurrentHub().startSpan({ + description: `${typeof options === 'string' ? 'GET' : options.method}|${requestUrl}`, + op: 'request', + }); + } + + return originalHandler + .apply(this, arguments) + .once('response', function(this: http.IncomingMessage, res: http.ServerResponse): void { + if (breadcrumbsEnabled) { + addRequestBreadcrumb('response', requestUrl, this, res); + } + if (tracingEnabled) { + span.setSuccess(); + span.finish(); + } + }) + .once('error', function(this: http.IncomingMessage): void { + if (breadcrumbsEnabled) { + addRequestBreadcrumb('error', requestUrl, this); + } + if (tracingEnabled) { + span.setFailure(); + span.finish(); + } + }); + }; + }; +} + +/** + * Captures Breadcrumb based on provided request/response pair + */ +function addRequestBreadcrumb(event: string, url: string, req: http.IncomingMessage, res?: http.ServerResponse): void { + if (!getCurrentHub().getIntegration(Http)) { + return; } + + getCurrentHub().addBreadcrumb( + { + category: 'http', + data: { + method: req.method, + status_code: res && res.statusCode, + url, + }, + type: 'http', + }, + { + event, + request: req, + response: res, + }, + ); } /** @@ -46,10 +135,7 @@ export class Http implements Integration { * @param options url that should be returned or an object containing it's parts. * @returns constructed url */ -function createBreadcrumbUrl(options: string | http.ClientRequestArgs): string { - // We could just always reconstruct this from this.agent, this._headers, this.path, etc - // but certain other http-instrumenting libraries (like nock, which we use for tests) fail to - // maintain the guarantee that after calling origClientRequest, those fields will be populated +function extractUrl(options: string | http.ClientRequestArgs): string { if (typeof options === 'string') { return options; } @@ -62,108 +148,19 @@ function createBreadcrumbUrl(options: string | http.ClientRequestArgs): string { } /** - * Wrapper function for internal _load calls within `require` - */ -function loadWrapper(nativeModule: any): any { - // We need to use some functional-style currying to pass values around - // as we cannot rely on `bind`, because this has to preserve correct - // context for native calls - return function(originalLoad: () => any): any { - return function(this: SentryRequest, moduleId: string): any { - const originalModule = originalLoad.apply(nativeModule, arguments); - - if (moduleId !== 'http' || originalModule.__sentry__) { - return originalModule; - } - - const origClientRequest = originalModule.ClientRequest; - const clientRequest = function( - this: SentryRequest, - options: http.ClientRequestArgs | string, - callback: () => void, - ): any { - // Note: this won't capture a breadcrumb if a response never comes - // It would be useful to know if that was the case, though, so - // TODO: revisit to see if we can capture sth indicating response never came - // possibility: capture one breadcrumb for "req sent" and one for "res recvd" - // seems excessive but solves the problem and *is* strictly more information - // could be useful for weird response sequencing bug scenarios - - origClientRequest.call(this, options, callback); - this.__ravenBreadcrumbUrl = createBreadcrumbUrl(options); - }; - - util.inherits(clientRequest, origClientRequest); - - fill(clientRequest.prototype, 'emit', emitWrapper); - - fill(originalModule, 'ClientRequest', function(): any { - return clientRequest; - }); - - // http.request orig refs module-internal ClientRequest, not exported one, so - // it still points at orig ClientRequest after our monkeypatch; these reimpls - // just get that reference updated to use our new ClientRequest - fill(originalModule, 'request', function(): any { - return function(options: http.ClientRequestArgs, callback: () => void): any { - return new originalModule.ClientRequest(options, callback) as http.IncomingMessage; - }; - }); - - fill(originalModule, 'get', function(): any { - return function(options: http.ClientRequestArgs, callback: () => void): any { - const req = originalModule.request(options, callback); - req.end(); - return req; - }; - }); - - originalModule.__sentry__ = true; - return originalModule; - }; - }; -} - -/** - * Wrapper function for request's `emit` calls + * Checks whether given url points to Sentry server + * @param url url to verify */ -function emitWrapper(origEmit: EventListener): (event: string, response: http.ServerResponse) => EventListener { - return function(this: SentryRequest, event: string, response: http.ServerResponse): any { - // I'm not sure why but Node.js (at least in v8.X) - // is emitting all events twice :| - if (lastResponse === undefined || lastResponse !== response) { - lastResponse = response; - } else { - return origEmit.apply(this, arguments); - } +function isSentryRequest(url: string): boolean { + const client = getCurrentHub().getClient(); + if (!url || !client) { + return false; + } - const client = getCurrentHub().getClient(); - if (client) { - const dsn = client.getDsn(); - - const isInterestingEvent = event === 'response' || event === 'error'; - const isNotSentryRequest = dsn && this.__ravenBreadcrumbUrl && this.__ravenBreadcrumbUrl.indexOf(dsn.host) === -1; - - if (isInterestingEvent && isNotSentryRequest && getCurrentHub().getIntegration(Http)) { - getCurrentHub().addBreadcrumb( - { - category: 'http', - data: { - method: this.method, - status_code: response.statusCode, - url: this.__ravenBreadcrumbUrl, - }, - type: 'http', - }, - { - event, - request: this, - response, - }, - ); - } - } + const dsn = client.getDsn(); + if (!dsn) { + return false; + } - return origEmit.apply(this, arguments); - }; + return url.indexOf(dsn.host) !== -1; } From a0e1f148217d1f24415b19b6ec015857de33e75c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Mon, 28 Oct 2019 14:04:46 +0100 Subject: [PATCH 27/63] feat: Rework console integration --- packages/node/src/integrations/console.ts | 105 ++++++++-------------- 1 file changed, 38 insertions(+), 67 deletions(-) diff --git a/packages/node/src/integrations/console.ts b/packages/node/src/integrations/console.ts index 1f38ada6f81c..7465d93df713 100644 --- a/packages/node/src/integrations/console.ts +++ b/packages/node/src/integrations/console.ts @@ -18,82 +18,53 @@ export class Console implements Integration { * @inheritDoc */ public setupOnce(): void { - const nativeModule = require('module'); - fill(nativeModule, '_load', loadWrapper(nativeModule)); - // special case: since console is built-in and app-level code won't require() it, do that here - require('console'); + const consoleModule = require('console'); + for (const level of ['debug', 'info', 'warn', 'error', 'log']) { + fill(consoleModule, level, createConsoleWrapper(level)); + } } } -/** - * Wrapper function for internal _load calls within `require` - */ -function loadWrapper(nativeModule: any): any { - // We need to use some functional-style currying to pass values around - // as we cannot rely on `bind`, because this has to preserve correct - // context for native calls - return function(originalLoad: () => any): any { - return function(moduleId: string): any { - const originalModule = originalLoad.apply(nativeModule, arguments); - - if (moduleId !== 'console' || originalModule.__sentry__) { - return originalModule; - } - - ['debug', 'info', 'warn', 'error', 'log'].forEach(consoleWrapper(originalModule)); - - originalModule.__sentry__ = true; - return originalModule; - }; - }; -} - /** * Wrapper function that'll be used for every console level */ -function consoleWrapper(originalModule: any): any { - return function(level: string): any { - if (!(level in originalModule)) { - return; - } +function createConsoleWrapper(level: string): (originalConsoleMethod: () => void) => void { + return function consoleWrapper(originalConsoleMethod: () => void): () => void { + let sentryLevel: Severity; - fill(originalModule, level, function(originalConsoleLevel: () => any): any { - let sentryLevel: Severity; + switch (level) { + case 'debug': + sentryLevel = Severity.Debug; + break; + case 'error': + sentryLevel = Severity.Error; + break; + case 'info': + sentryLevel = Severity.Info; + break; + case 'warn': + sentryLevel = Severity.Warning; + break; + default: + sentryLevel = Severity.Log; + } - switch (level) { - case 'debug': - sentryLevel = Severity.Debug; - break; - case 'error': - sentryLevel = Severity.Error; - break; - case 'info': - sentryLevel = Severity.Info; - break; - case 'warn': - sentryLevel = Severity.Warning; - break; - default: - sentryLevel = Severity.Log; + return function(this: typeof console): void { + if (getCurrentHub().getIntegration(Console)) { + getCurrentHub().addBreadcrumb( + { + category: 'console', + level: sentryLevel, + message: util.format.apply(undefined, arguments), + }, + { + input: [...arguments], + level, + }, + ); } - return function(): any { - if (getCurrentHub().getIntegration(Console)) { - getCurrentHub().addBreadcrumb( - { - category: 'console', - level: sentryLevel, - message: util.format.apply(undefined, arguments), - }, - { - input: [...arguments], - level, - }, - ); - } - - originalConsoleLevel.apply(originalModule, arguments); - }; - }); + originalConsoleMethod.apply(this, arguments); + }; }; } From 53a5d351ec8323153a388dcb7db6e1e97358deb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Mon, 28 Oct 2019 14:05:03 +0100 Subject: [PATCH 28/63] feat: tracingHandler for APM --- packages/node/src/handlers.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/packages/node/src/handlers.ts b/packages/node/src/handlers.ts index 3eab9be25c3e..d823080d508d 100644 --- a/packages/node/src/handlers.ts +++ b/packages/node/src/handlers.ts @@ -12,6 +12,39 @@ import { flush } from './sdk'; const DEFAULT_SHUTDOWN_TIMEOUT = 2000; +/** + * Express compatible tracing handler. + * @see Exposed as `Handlers.tracingHandler` + */ +export function tracingHandler(): ( + req: http.IncomingMessage, + res: http.ServerResponse, + next: (error?: any) => void, +) => void { + return function sentryTracingMiddleware( + req: http.IncomingMessage, + res: http.ServerResponse, + next: (error?: any) => void, + ): void { + // TODO: At this point req.route.path we use in `extractTransaction` is not available + // but `req.path` or `req.url` should do the job as well. We could unify this here. + const reqMethod = (req.method || '').toUpperCase(); + const reqUrl = req.url; + const hub = getCurrentHub(); + const transaction = hub.startSpan({ + transaction: `${reqMethod}|${reqUrl}`, + }); + hub.configureScope(scope => { + scope.setSpan(transaction); + }); + res + .once('response', () => transaction.setSuccess()) + .once('error', () => transaction.setFailure()) + .once('finish', () => transaction.finish()); + next(); + }; +} + type TransactionTypes = 'path' | 'methodPath' | 'handler'; /** JSDoc */ From d5b3df60c34fca52e818b09df607372232fabf99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Mon, 28 Oct 2019 14:05:16 +0100 Subject: [PATCH 29/63] feat: Express middleware tracing integration --- packages/integrations/src/express.ts | 124 +++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 packages/integrations/src/express.ts diff --git a/packages/integrations/src/express.ts b/packages/integrations/src/express.ts new file mode 100644 index 000000000000..60e3e2f4b786 --- /dev/null +++ b/packages/integrations/src/express.ts @@ -0,0 +1,124 @@ +import { EventProcessor, Hub, Integration } from '@sentry/types'; +import { logger } from '@sentry/utils'; +import { Application, ErrorRequestHandler, NextFunction, Request, RequestHandler, Response } from 'express'; + +/** + * Express integration + * + * Provides an request and error handler for Express framework + * as well as tracing capabilities + */ +export class Express implements Integration { + /** + * @inheritDoc + */ + public name: string = Express.id; + + /** + * @inheritDoc + */ + public static id: string = 'Express'; + + /** + * Express App instance + */ + private readonly _app?: Application; + + /** + * @inheritDoc + */ + public constructor(options: { app?: Application } = {}) { + this._app = options.app; + } + + /** + * @inheritDoc + */ + public setupOnce(_addGlobalEventProcessor: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void { + if (!this._app) { + logger.error('ExpressIntegration is missing an Express instancex'); + return; + } + instrumentMiddlewares(this._app, getCurrentHub); + } +} + +/** + * JSDoc + */ +function wrap(fn: Function, getCurrentHub: () => Hub): RequestHandler | ErrorRequestHandler { + const arrity = fn.length; + + switch (arrity) { + case 2: { + return function(this: NodeJS.Global, _req: Request, res: Response): any { + const span = getCurrentHub().startSpan({ + description: fn.name, + op: 'middleware', + }); + res.once('finish', () => span.finish()); + return fn.apply(this, arguments); + }; + } + case 3: { + return function(this: NodeJS.Global, req: Request, res: Response, next: NextFunction): any { + const span = getCurrentHub().startSpan({ + description: fn.name, + op: 'middleware', + }); + fn.call(this, req, res, function(this: NodeJS.Global): any { + span.finish(); + return next.apply(this, arguments); + }); + }; + } + case 4: { + return function(this: NodeJS.Global, err: any, req: Request, res: Response, next: NextFunction): any { + const span = getCurrentHub().startSpan({ + description: fn.name, + op: 'middleware', + }); + fn.call(this, err, req, res, function(this: NodeJS.Global): any { + span.finish(); + return next.apply(this, arguments); + }); + }; + } + default: { + throw new Error(`Express middleware takes 2-4 arguments. Got: ${arrity}`); + } + } +} + +/** + * JSDoc + */ +function wrapUseArgs(args: IArguments, getCurrentHub: () => Hub): unknown[] { + return Array.from(args).map((arg: unknown) => { + if (typeof arg === 'function') { + return wrap(arg, getCurrentHub); + } + + if (Array.isArray(arg)) { + return arg.map((a: unknown) => { + if (typeof a === 'function') { + return wrap(a, getCurrentHub); + } + return a; + }); + } + + return arg; + }); +} + +/** + * JSDoc + */ +function instrumentMiddlewares(app: Application, getCurrentHub: () => Hub): any { + const originalAppUse = app.use; + app.use = function(): any { + return originalAppUse.apply(this, wrapUseArgs(arguments, getCurrentHub)); + }; + return app; +} From 74eacc00225211d36558355bde1672334b9e52f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Mon, 28 Oct 2019 17:35:27 +0100 Subject: [PATCH 30/63] fix: Make rewritten http integration work in pre v9 node versions --- packages/node/src/integrations/http.ts | 17 ++++++++++---- packages/utils/src/misc.ts | 32 ++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/packages/node/src/integrations/http.ts b/packages/node/src/integrations/http.ts index 0b2b7f608d3e..88099faa4bed 100644 --- a/packages/node/src/integrations/http.ts +++ b/packages/node/src/integrations/http.ts @@ -1,9 +1,11 @@ import { getCurrentHub, Span } from '@sentry/core'; import { Integration } from '@sentry/types'; -import { fill } from '@sentry/utils'; +import { fill, parseSemver } from '@sentry/utils'; import * as http from 'http'; import * as https from 'https'; +const NODE_VERSION = parseSemver(process.versions.node); + /** http module integration */ export class Http implements Integration { /** @@ -48,9 +50,14 @@ export class Http implements Integration { fill(httpModule, 'get', handlerWrapper); fill(httpModule, 'request', handlerWrapper); - const httpsModule = require('https'); - fill(httpsModule, 'get', handlerWrapper); - fill(httpsModule, 'request', handlerWrapper); + // NOTE: Prior to Node 9, `https` used internals of `http` module, thus we don't patch it. + // If we do, we'd get double breadcrumbs and double spans for `https` calls. + // It has been changed in Node 9, so for all versions equal and above, we patch `https` separately. + if (NODE_VERSION.major && NODE_VERSION.major > 8) { + const httpsModule = require('https'); + fill(httpsModule, 'get', handlerWrapper); + fill(httpsModule, 'request', handlerWrapper); + } } } @@ -74,7 +81,7 @@ function createHandlerWrapper( let span: Span; if (tracingEnabled) { span = getCurrentHub().startSpan({ - description: `${typeof options === 'string' ? 'GET' : options.method}|${requestUrl}`, + description: `${typeof options === 'string' || !options.method ? 'GET' : options.method}|${requestUrl}`, op: 'request', }); } diff --git a/packages/utils/src/misc.ts b/packages/utils/src/misc.ts index 30e1d741b298..2696df3acebc 100644 --- a/packages/utils/src/misc.ts +++ b/packages/utils/src/misc.ts @@ -342,3 +342,35 @@ function _htmlElementAsString(elem: HTMLElement): string { export function timestampWithMs(): number { return new Date().getTime() / 1000; } + +// https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string +const SEMVER_REGEXP = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/; + +/** + * Represents Semantic Versioning object + */ +interface SemVer { + major?: number; + minor?: number; + patch?: number; + prerelease?: string; + buildmetadata?: string; +} + +/** + * Parses input into a SemVer interface + * @param input string representation of a semver version + */ +export function parseSemver(input: string): SemVer { + const match = input.match(SEMVER_REGEXP) || []; + const major = parseInt(match[1], 10); + const minor = parseInt(match[2], 10); + const patch = parseInt(match[3], 10); + return { + buildmetadata: match[5], + major: isNaN(major) ? undefined : major, + minor: isNaN(minor) ? undefined : minor, + patch: isNaN(patch) ? undefined : patch, + prerelease: match[4], + }; +} From e58a8de9aba646f6c2083259332f0fea7d215f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Tue, 29 Oct 2019 11:56:50 +0100 Subject: [PATCH 31/63] ref: Mark failed transactions --- packages/node/src/handlers.ts | 12 ++++++++---- packages/node/src/integrations/http.ts | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/node/src/handlers.ts b/packages/node/src/handlers.ts index d823080d508d..d1be08ecc5bc 100644 --- a/packages/node/src/handlers.ts +++ b/packages/node/src/handlers.ts @@ -37,10 +37,14 @@ export function tracingHandler(): ( hub.configureScope(scope => { scope.setSpan(transaction); }); - res - .once('response', () => transaction.setSuccess()) - .once('error', () => transaction.setFailure()) - .once('finish', () => transaction.finish()); + res.once('finish', () => { + if (res.statusCode >= 500) { + transaction.setFailure(); + } else { + transaction.setSuccess(); + } + transaction.finish(); + }); next(); }; } diff --git a/packages/node/src/integrations/http.ts b/packages/node/src/integrations/http.ts index 88099faa4bed..f22a2b91c14d 100644 --- a/packages/node/src/integrations/http.ts +++ b/packages/node/src/integrations/http.ts @@ -92,6 +92,7 @@ function createHandlerWrapper( if (breadcrumbsEnabled) { addRequestBreadcrumb('response', requestUrl, this, res); } + // TODO: Mark >= 500 as failed as well? if (tracingEnabled) { span.setSuccess(); span.finish(); From 5ca412aa2aaaaadde53e900733c274d3b6cdb427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Tue, 29 Oct 2019 12:17:11 +0100 Subject: [PATCH 32/63] Remove express types from deps and add better docs --- packages/integrations/src/express.ts | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/integrations/src/express.ts b/packages/integrations/src/express.ts index 60e3e2f4b786..c04256ec4605 100644 --- a/packages/integrations/src/express.ts +++ b/packages/integrations/src/express.ts @@ -44,7 +44,16 @@ export class Express implements Integration { } /** - * JSDoc + * Wraps original middleware function in a tracing call, which stores the info about the call as a span, + * and finishes it once the middleware is done invoking. + * + * Express middlewares have 3 various forms, thus we have to take care of all of them: + * // sync + * app.use(function (req, res) { ... }) + * // async + * app.use(function (req, res, next) { ... }) + * // error handler + * app.use(function (err, req, res, next) { ... }) */ function wrap(fn: Function, getCurrentHub: () => Hub): RequestHandler | ErrorRequestHandler { const arrity = fn.length; @@ -91,7 +100,14 @@ function wrap(fn: Function, getCurrentHub: () => Hub): RequestHandler | ErrorReq } /** - * JSDoc + * Takes all the function arguments passed to the original `app.use` call + * and wraps every function, as well as array of functions with a call to our `wrap` method. + * We have to take care of the arrays as well as iterate over all of the arguments, + * as `app.use` can accept middlewares in few various forms. + * + * app.use([], ) + * app.use([], , ...) + * app.use([], ...[]) */ function wrapUseArgs(args: IArguments, getCurrentHub: () => Hub): unknown[] { return Array.from(args).map((arg: unknown) => { @@ -113,9 +129,9 @@ function wrapUseArgs(args: IArguments, getCurrentHub: () => Hub): unknown[] { } /** - * JSDoc + * Patches original app.use to utilize our tracing functionality */ -function instrumentMiddlewares(app: Application, getCurrentHub: () => Hub): any { +function instrumentMiddlewares(app: Application, getCurrentHub: () => Hub): Application { const originalAppUse = app.use; app.use = function(): any { return originalAppUse.apply(this, wrapUseArgs(arguments, getCurrentHub)); From 2b21ff7d43fbdf78d2251c929d8e8ab3e8f9dec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Fri, 1 Nov 2019 12:06:00 +0100 Subject: [PATCH 33/63] ref: Pre-release linter and tests patches --- packages/hub/src/hub.ts | 3 +- packages/hub/src/span.ts | 8 +-- packages/hub/test/span.test.ts | 8 +-- packages/integrations/src/express.ts | 1 + packages/node/src/handlers.ts | 2 +- yarn.lock | 74 ++++++++++++++++++++++------ 6 files changed, 70 insertions(+), 26 deletions(-) diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index 737a26c8ac7c..3a78a4f18165 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -430,8 +430,7 @@ export class Hub implements HubInterface { if (span.sampled) { const experimentsOptions = (client && client.getOptions()._experiments) || {}; - const maxSpans = experimentsOptions.maxSpans || 1000; - span.initFinishedSpans(maxSpans); + span.initFinishedSpans(experimentsOptions.maxSpans); } return span; diff --git a/packages/hub/src/span.ts b/packages/hub/src/span.ts index 10dc7e4e0ad2..fa6c9b9486c2 100644 --- a/packages/hub/src/span.ts +++ b/packages/hub/src/span.ts @@ -134,7 +134,8 @@ export class Span implements SpanInterface, SpanContext { if (spanContext.parentSpanId) { this._parentSpanId = spanContext.parentSpanId; } - if (spanContext.sampled) { + // We want to include booleans as well here + if ('sampled' in spanContext) { this.sampled = spanContext.sampled; } if (spanContext.transaction) { @@ -158,7 +159,7 @@ export class Span implements SpanInterface, SpanContext { * Attaches SpanRecorder to the span itself * @param maxlen maximum number of spans that can be recorded */ - public initFinishedSpans(maxlen: number): void { + public initFinishedSpans(maxlen: number = 1000): void { if (!this.spanRecorder) { this.spanRecorder = new SpanRecorder(maxlen); } @@ -288,8 +289,7 @@ export class Span implements SpanInterface, SpanContext { logger.warn('Discarding transaction Span without sampling decision'); return undefined; } - - const finishedSpans = !this.spanRecorder ? [] : this.spanRecorder.finishedSpans.filter(s => s !== this); + const finishedSpans = this.spanRecorder ? this.spanRecorder.finishedSpans.filter(s => s !== this) : []; return this._hub.captureEvent({ // TODO: Is this necessary? We already do store contextx in in applyToEvent, diff --git a/packages/hub/test/span.test.ts b/packages/hub/test/span.test.ts index 42d3c873133b..7cd61e01d2e5 100644 --- a/packages/hub/test/span.test.ts +++ b/packages/hub/test/span.test.ts @@ -169,15 +169,17 @@ describe('Span', () => { test('finish a scope span with transaction', () => { const spy = jest.spyOn(hub as any, 'captureEvent') as any; - const span = new Span({ transaction: 'test' }, hub); + const span = new Span({ transaction: 'test', sampled: false }, hub); + span.initFinishedSpans(); span.finish(); expect(spy).toHaveBeenCalled(); - expect(spy.mock.calls[0][0].spans).toBeUndefined(); + expect(spy.mock.calls[0][0].spans).toHaveLength(0); }); test('finish a scope span with transaction + child span', () => { const spy = jest.spyOn(hub as any, 'captureEvent') as any; - const parentSpan = new Span({ transaction: 'test' }, hub); + const parentSpan = new Span({ transaction: 'test', sampled: false }, hub); + parentSpan.initFinishedSpans(); const childSpan = parentSpan.child(); childSpan.finish(); parentSpan.finish(); diff --git a/packages/integrations/src/express.ts b/packages/integrations/src/express.ts index c04256ec4605..6916f849c360 100644 --- a/packages/integrations/src/express.ts +++ b/packages/integrations/src/express.ts @@ -1,5 +1,6 @@ import { EventProcessor, Hub, Integration } from '@sentry/types'; import { logger } from '@sentry/utils'; +// tslint:disable-next-line:no-implicit-dependencies import { Application, ErrorRequestHandler, NextFunction, Request, RequestHandler, Response } from 'express'; /** diff --git a/packages/node/src/handlers.ts b/packages/node/src/handlers.ts index d1be08ecc5bc..60875f6571c8 100644 --- a/packages/node/src/handlers.ts +++ b/packages/node/src/handlers.ts @@ -1,4 +1,4 @@ -import { captureException, getCurrentHub } from '@sentry/core'; +import { captureException, getCurrentHub, Span, withScope } from '@sentry/core'; import { Event } from '@sentry/types'; import { forget, isString, logger, normalize } from '@sentry/utils'; import * as cookie from 'cookie'; diff --git a/yarn.lock b/yarn.lock index 0c5164ffb3c8..2d5e53e6ab59 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1193,6 +1193,14 @@ dependencies: "@babel/types" "^7.3.0" +"@types/body-parser@*": + version "1.17.1" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.1.tgz#18fcf61768fb5c30ccc508c21d6fd2e8b3bf7897" + integrity sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w== + dependencies: + "@types/connect" "*" + "@types/node" "*" + "@types/caseless@*": version "0.12.1" resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.1.tgz#9794c69c8385d0192acc471a540d1f8e0d16218a" @@ -1202,10 +1210,17 @@ resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.7.tgz#1b8e33b61a8c09cbe1f85133071baa0dbf9fa71a" integrity sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA== -"@types/cookie@^0.3.2": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.3.tgz#85bc74ba782fb7aa3a514d11767832b0e3bc6803" - integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow== +"@types/connect@*": + version "3.4.32" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.32.tgz#aa0e9616b9435ccad02bc52b5b454ffc2c70ba28" + integrity sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg== + dependencies: + "@types/node" "*" + +"@types/cookie@0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.2.tgz#453f4b14b25da6a8ea4494842dedcbf0151deef9" + integrity sha512-aHQA072E10/8iUQsPH7mQU/KUyQBZAGzTVRCUvnSz8mSvbrYsP4xEO2RSA0Pjltolzi0j8+8ixrm//Hr4umPzw== "@types/estree@0.0.39": version "0.0.39" @@ -1217,6 +1232,23 @@ resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== +"@types/express-serve-static-core@*": + version "4.16.10" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.10.tgz#3c1313c6e6b75594561b473a286f016a9abf2132" + integrity sha512-gM6evDj0OvTILTRKilh9T5dTaGpv1oYiFcJAfgSejuMJgGJUsD9hKEU2lB4aiTNy4WwChxRnjfYFuBQsULzsJw== + dependencies: + "@types/node" "*" + "@types/range-parser" "*" + +"@types/express@^4.17.1": + version "4.17.1" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.1.tgz#4cf7849ae3b47125a567dfee18bfca4254b88c5c" + integrity sha512-VfH/XCP0QbQk5B5puLqTLEeFgR8lfCJHZJKkInZ9mkYd+u8byX0kztXEQxEk4wZXJs8HI+7km2ALXjn4YKcX9w== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "*" + "@types/serve-static" "*" + "@types/form-data@*": version "2.2.1" resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.2.1.tgz#ee2b3b8eaa11c0938289953606b745b738c54b1e" @@ -1288,6 +1320,11 @@ dependencies: "@types/node" "*" +"@types/mime@*": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" + integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw== + "@types/minimatch@*", "@types/minimatch@3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" @@ -1308,6 +1345,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-11.13.7.tgz#85dbb71c510442d00c0631f99dae957ce44fd104" integrity sha512-suFHr6hcA9mp8vFrZTgrmqW2ZU3mbWsryQtQlY/QvwTISCw7nw/j+bCQPPohqmskhmqa5wLNuMHTTsc+xf1MQg== +"@types/range-parser@*": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" + integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== + "@types/raven@^2.5.1": version "2.5.3" resolved "https://registry.yarnpkg.com/@types/raven/-/raven-2.5.3.tgz#bd4bed667dd9cfda39452f8ed64a87f45233bc3a" @@ -1332,6 +1374,14 @@ dependencies: "@types/node" "*" +"@types/serve-static@*": + version "1.13.3" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.3.tgz#eb7e1c41c4468272557e897e9171ded5e2ded9d1" + integrity sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g== + dependencies: + "@types/express-serve-static-core" "*" + "@types/mime" "*" + "@types/shelljs@^0.8.0": version "0.8.3" resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.3.tgz#f713f312dbae49ab5025290007e71ea32998e9a9" @@ -1597,7 +1647,7 @@ after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" -agent-base@4, agent-base@4.3.0, agent-base@^4.1.0, agent-base@^4.3.0, agent-base@~4.2.0: +agent-base@4, agent-base@4.3.0, agent-base@^4.1.0, agent-base@~4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== @@ -3514,7 +3564,7 @@ cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" -cookie@0.3.1, cookie@^0.3.1: +cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" @@ -5432,21 +5482,13 @@ https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" -https-proxy-agent@^2.2.1: +https-proxy-agent@2.2.1, https-proxy-agent@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" dependencies: agent-base "^4.1.0" debug "^3.1.0" -https-proxy-agent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-3.0.0.tgz#0106efa5d63d6d6f3ab87c999fa4877a3fd1ff97" - integrity sha512-y4jAxNEihqvBI5F3SaO2rtsjIOnnNA8sEbuiP+UhJZJHeM2NRm6c09ax2tgqme+SgUUvjao2fJXF4h3D6Cb2HQ== - dependencies: - agent-base "^4.3.0" - debug "^3.1.0" - humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" @@ -7185,7 +7227,7 @@ lru-cache@^5.0.0, lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lru_map@^0.3.3: +lru_map@0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0= From 0dfcdc9e4d3edecd2b3d00c59eafd0ea8eaf8d92 Mon Sep 17 00:00:00 2001 From: HazA Date: Fri, 1 Nov 2019 09:56:24 +0100 Subject: [PATCH 34/63] meta: Bump to 5.8.0-beta.0 --- lerna.json | 2 +- packages/browser/package.json | 9 +++++---- packages/browser/src/version.ts | 2 +- packages/core/package.json | 10 +++++----- packages/hub/package.json | 6 +++--- packages/integrations/package.json | 7 ++++--- packages/minimal/package.json | 6 +++--- packages/node/package.json | 18 +++++++++--------- packages/node/src/version.ts | 2 +- packages/types/package.json | 2 +- packages/typescript/package.json | 2 +- packages/utils/package.json | 4 ++-- 12 files changed, 36 insertions(+), 34 deletions(-) diff --git a/lerna.json b/lerna.json index 807488477620..894362259599 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "3.4.0", - "version": "5.7.1", + "version": "5.8.0-beta.0", "packages": "packages/*", "ignore": "raven-*", "npmClient": "yarn", diff --git a/packages/browser/package.json b/packages/browser/package.json index f5cefa96482f..e392f50a0771 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/browser", - "version": "5.7.1", + "version": "5.8.0-beta.0", "description": "Official Sentry SDK for browsers", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/browser", @@ -16,9 +16,9 @@ "access": "public" }, "dependencies": { - "@sentry/core": "5.7.1", - "@sentry/types": "5.7.1", - "@sentry/utils": "5.7.1", + "@sentry/core": "5.8.0-beta.0", + "@sentry/types": "5.8.0-beta.0", + "@sentry/utils": "5.8.0-beta.0", "tslib": "^1.9.3" }, "devDependencies": { @@ -43,6 +43,7 @@ "rollup": "^1.10.1", "rollup-plugin-commonjs": "^9.3.4", "rollup-plugin-license": "^0.8.1", + "rollup-plugin-modify": "^3.0.0", "rollup-plugin-node-resolve": "^4.2.3", "rollup-plugin-terser": "^4.0.4", "rollup-plugin-typescript2": "^0.21.0", diff --git a/packages/browser/src/version.ts b/packages/browser/src/version.ts index 7d41d25d04e1..8071e9e930f9 100644 --- a/packages/browser/src/version.ts +++ b/packages/browser/src/version.ts @@ -1,2 +1,2 @@ export const SDK_NAME = 'sentry.javascript.browser'; -export const SDK_VERSION = '5.7.1'; +export const SDK_VERSION = '5.8.0-beta.0'; diff --git a/packages/core/package.json b/packages/core/package.json index 30fd385360f7..28a284371045 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/core", - "version": "5.7.1", + "version": "5.8.0-beta.0", "description": "Base implementation for all Sentry JavaScript SDKs", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/core", @@ -16,10 +16,10 @@ "access": "public" }, "dependencies": { - "@sentry/hub": "5.7.1", - "@sentry/minimal": "5.7.1", - "@sentry/types": "5.7.1", - "@sentry/utils": "5.7.1", + "@sentry/hub": "5.8.0-beta.0", + "@sentry/minimal": "5.8.0-beta.0", + "@sentry/types": "5.8.0-beta.0", + "@sentry/utils": "5.8.0-beta.0", "tslib": "^1.9.3" }, "devDependencies": { diff --git a/packages/hub/package.json b/packages/hub/package.json index aed0dcc0c1f9..c90978ab1d7b 100644 --- a/packages/hub/package.json +++ b/packages/hub/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/hub", - "version": "5.7.1", + "version": "5.8.0-beta.0", "description": "Sentry hub which handles global state managment.", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/hub", @@ -16,8 +16,8 @@ "access": "public" }, "dependencies": { - "@sentry/types": "5.7.1", - "@sentry/utils": "5.7.1", + "@sentry/types": "5.8.0-beta.0", + "@sentry/utils": "5.8.0-beta.0", "tslib": "^1.9.3" }, "devDependencies": { diff --git a/packages/integrations/package.json b/packages/integrations/package.json index afd8258bc3f3..29021cb1550e 100644 --- a/packages/integrations/package.json +++ b/packages/integrations/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/integrations", - "version": "5.7.1", + "version": "5.8.0-beta.0", "description": "Pluggable integrations that can be used to enchance JS SDKs", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/integrations", @@ -16,11 +16,12 @@ "module": "esm/index.js", "types": "dist/index.d.ts", "dependencies": { - "@sentry/types": "5.7.1", - "@sentry/utils": "5.7.1", + "@sentry/types": "5.8.0-beta.0", + "@sentry/utils": "5.8.0-beta.0", "tslib": "^1.9.3" }, "devDependencies": { + "@types/express": "^4.17.1", "chai": "^4.1.2", "jest": "^24.7.1", "npm-run-all": "^4.1.2", diff --git a/packages/minimal/package.json b/packages/minimal/package.json index 4bf0b4d78372..11a326f80f39 100644 --- a/packages/minimal/package.json +++ b/packages/minimal/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/minimal", - "version": "5.7.1", + "version": "5.8.0-beta.0", "description": "Sentry minimal library that can be used in other packages", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/minimal", @@ -16,8 +16,8 @@ "access": "public" }, "dependencies": { - "@sentry/hub": "5.7.1", - "@sentry/types": "5.7.1", + "@sentry/hub": "5.8.0-beta.0", + "@sentry/types": "5.8.0-beta.0", "tslib": "^1.9.3" }, "devDependencies": { diff --git a/packages/node/package.json b/packages/node/package.json index b3d0923fbd1a..8ec46674f8be 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/node", - "version": "5.7.1", + "version": "5.8.0-beta.0", "description": "Offical Sentry SDK for Node.js", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/node", @@ -16,17 +16,17 @@ "access": "public" }, "dependencies": { - "@sentry/core": "5.7.1", - "@sentry/hub": "5.7.1", - "@sentry/types": "5.7.1", - "@sentry/utils": "5.7.1", - "cookie": "^0.3.1", - "https-proxy-agent": "^3.0.0", - "lru_map": "^0.3.3", + "@sentry/core": "5.8.0-beta.0", + "@sentry/hub": "5.8.0-beta.0", + "@sentry/types": "5.8.0-beta.0", + "@sentry/utils": "5.8.0-beta.0", + "cookie": "0.3.1", + "https-proxy-agent": "2.2.1", + "lru_map": "0.3.3", "tslib": "^1.9.3" }, "devDependencies": { - "@types/cookie": "^0.3.2", + "@types/cookie": "0.3.2", "@types/lru-cache": "^5.1.0", "@types/node": "^11.13.7", "express": "^4.16.4", diff --git a/packages/node/src/version.ts b/packages/node/src/version.ts index 4a3c93786a16..ba2c3f52a465 100644 --- a/packages/node/src/version.ts +++ b/packages/node/src/version.ts @@ -1,2 +1,2 @@ export const SDK_NAME = 'sentry.javascript.node'; -export const SDK_VERSION = '5.7.1'; +export const SDK_VERSION = '5.8.0-beta.0'; diff --git a/packages/types/package.json b/packages/types/package.json index cfb39a677512..0538a46ce200 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/types", - "version": "5.7.1", + "version": "5.8.0-beta.0", "description": "Types for all Sentry JavaScript SDKs", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/types", diff --git a/packages/typescript/package.json b/packages/typescript/package.json index f7c8dba71024..25642a0f0b2f 100644 --- a/packages/typescript/package.json +++ b/packages/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/typescript", - "version": "5.7.1", + "version": "5.8.0-beta.0", "description": "Typescript configuration used at Sentry", "repository": "git://github.com/getsentry/raven-js.git", "homepage": "https://github.com/getsentry/raven-js/tree/master/packages/typescript", diff --git a/packages/utils/package.json b/packages/utils/package.json index 385af8633993..4defa4ae127b 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/utils", - "version": "5.7.1", + "version": "5.8.0-beta.0", "description": "Utilities for all Sentry JavaScript SDKs", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/utils", @@ -16,7 +16,7 @@ "access": "public" }, "dependencies": { - "@sentry/types": "5.7.1", + "@sentry/types": "5.8.0-beta.0", "tslib": "^1.9.3" }, "devDependencies": { From 4e68f8fdda2d8ce8a4a1d309f76c6d5af18687ff Mon Sep 17 00:00:00 2001 From: HazA Date: Thu, 7 Nov 2019 15:24:44 +0100 Subject: [PATCH 35/63] feat: TransactionActivity Integration --- .../integrations/src/transactionactivity.ts | 151 ++++++++++++++++++ .../test/transactionactivity.test.ts | 62 +++++++ 2 files changed, 213 insertions(+) create mode 100644 packages/integrations/src/transactionactivity.ts create mode 100644 packages/integrations/test/transactionactivity.test.ts diff --git a/packages/integrations/src/transactionactivity.ts b/packages/integrations/src/transactionactivity.ts new file mode 100644 index 000000000000..b4c83f3f18e2 --- /dev/null +++ b/packages/integrations/src/transactionactivity.ts @@ -0,0 +1,151 @@ +import { EventProcessor, Hub, Integration, Scope, Span, SpanContext } from '@sentry/types'; + +/** JSDoc */ +interface TransactionActivityOptions { + // onLocationChange: (info) => { + // // info holds the location change api. + // // if this returns `null` there is no transaction started. + // return info.state.transaction || info.url; + // }, + // onActivity?: (info) => { + // return info.type !== 'xhr' || !info.url.match(/zendesk/); + // }, + idleTimeout?: number; +} + +/** JSDoc */ +interface Activity { + name: string; + span?: Span; +} + +/** JSDoc */ +export class TransactionActivity implements Integration { + /** + * @inheritDoc + */ + public name: string = TransactionActivity.id; + + /** + * @inheritDoc + */ + public static id: string = 'TransactionActivity'; + + /** JSDoc */ + private static _options: TransactionActivityOptions; + + /** + * Returns current hub. + */ + private static _getCurrentHub?: () => Hub; + + private static _activeTransaction?: Span; + + private static _currentIndex: number = 0; + + private static readonly _activities: { [key: number]: Activity } = {}; + + private static _debounce: number = 0; + + /** + * @inheritDoc + */ + public constructor(options?: TransactionActivityOptions) { + TransactionActivity._options = { + idleTimeout: 500, + ...options, + }; + } + + /** + * @inheritDoc + */ + public setupOnce(_: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void { + TransactionActivity._getCurrentHub = getCurrentHub; + } + + /** + * Internal run loop that checks if activy is running + */ + private static _watchActivity(): void { + const count = Object.keys(TransactionActivity._activities).length; + if (count > 0) { + clearTimeout(TransactionActivity._debounce); + setTimeout(() => { + TransactionActivity._watchActivity(); + }, 10); + } else { + TransactionActivity._debounce = (setTimeout(() => { + const active = TransactionActivity._activeTransaction; + if (active) { + active.finish(); + } + }, (TransactionActivity._options && TransactionActivity._options.idleTimeout) || 500) as any) as number; // TODO 500 + } + } + + /** + * Starts a Transaction waiting for activity idle to finish + */ + public static startIdleTransaction(name: string, spanContext?: SpanContext): Span | undefined { + const _getCurrentHub = TransactionActivity._getCurrentHub; + if (!_getCurrentHub) { + return undefined; + } + + const hub = _getCurrentHub(); + if (!hub) { + return undefined; + } + + const span = hub.startSpan({ + ...spanContext, + transaction: name, + }); + + TransactionActivity._activeTransaction = span; + + hub.configureScope((scope: Scope) => { + scope.setSpan(span); + }); + + return span; + } + + /** + * Starts tracking for a specifc activity + */ + public static pushActivity(name: string, spanContext?: SpanContext): number { + const _getCurrentHub = TransactionActivity._getCurrentHub; + if (spanContext && _getCurrentHub) { + const hub = _getCurrentHub(); + if (hub) { + TransactionActivity._activities[TransactionActivity._currentIndex] = { + name, + span: hub.startSpan(spanContext), + }; + } + } else { + TransactionActivity._activities[TransactionActivity._currentIndex] = { + name, + }; + } + + TransactionActivity._watchActivity(); + return TransactionActivity._currentIndex++; + } + + /** + * Removes activity and finishes the span in case there is one + */ + public static popActivity(id: number): void { + const activity = TransactionActivity._activities[id]; + if (activity) { + if (activity.span) { + activity.span.finish(); + } + // tslint:disable-next-line: no-dynamic-delete + delete TransactionActivity._activities[id]; + } + } +} diff --git a/packages/integrations/test/transactionactivity.test.ts b/packages/integrations/test/transactionactivity.test.ts new file mode 100644 index 000000000000..842bbc4a99b5 --- /dev/null +++ b/packages/integrations/test/transactionactivity.test.ts @@ -0,0 +1,62 @@ +import { TransactionActivity } from '../src/transactionactivity'; + +const transactionActivity: TransactionActivity = new TransactionActivity(); + +const configureScope: any = jest.fn(); +const startSpan: any = jest.fn(); + +const getCurrentHubMock: any = () => ({ + configureScope, + startSpan, +}); + +transactionActivity.setupOnce(jest.fn(), getCurrentHubMock); + +describe('TransactionActivity', () => { + afterEach(() => { + jest.resetAllMocks(); + (TransactionActivity as any)._activities = {}; + (TransactionActivity as any)._currentIndex = 0; + (TransactionActivity as any)._activeTransaction = undefined; + }); + + test('startSpan with transaction', () => { + TransactionActivity.startIdleTransaction('test'); + expect(startSpan).toBeCalled(); + expect(startSpan.mock.calls[0][0].transaction).toBe('test'); + }); + + test('track activity', () => { + jest.useFakeTimers(); + const spy = jest.spyOn(TransactionActivity as any, '_watchActivity'); + + TransactionActivity.pushActivity('xhr'); + expect(spy).toBeCalledTimes(1); + jest.runOnlyPendingTimers(); + expect(spy).toBeCalledTimes(2); + jest.runOnlyPendingTimers(); + expect(spy).toBeCalledTimes(3); + }); + + test('multiple activities ', () => { + TransactionActivity.pushActivity('xhr'); + const a = TransactionActivity.pushActivity('xhr2'); + TransactionActivity.popActivity(a); + TransactionActivity.pushActivity('xhr3'); + expect(Object.keys((TransactionActivity as any)._activities)).toHaveLength(2); + }); + + test.only('finishing a transaction after debounce', () => { + jest.useFakeTimers(); + const spy = jest.spyOn(TransactionActivity as any, '_watchActivity'); + TransactionActivity.startIdleTransaction('test'); + const a = TransactionActivity.pushActivity('xhr'); + expect(spy).toBeCalledTimes(1); + expect(Object.keys((TransactionActivity as any)._activities)).toHaveLength(1); + TransactionActivity.popActivity(a); + expect(Object.keys((TransactionActivity as any)._activities)).toHaveLength(0); + jest.runOnlyPendingTimers(); + expect(spy).toBeCalledTimes(2); + expect((TransactionActivity as any)._debounce).toBeTruthy(); + }); +}); From b6c959ec1124f4e8f57120e64567b7b214c79b3f Mon Sep 17 00:00:00 2001 From: HazA Date: Thu, 7 Nov 2019 15:38:27 +0100 Subject: [PATCH 36/63] feat: Finish transaction with timestamp --- packages/hub/src/span.ts | 4 ++-- packages/integrations/src/transactionactivity.ts | 5 +++-- packages/types/src/span.ts | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/hub/src/span.ts b/packages/hub/src/span.ts index fa6c9b9486c2..33b84078c121 100644 --- a/packages/hub/src/span.ts +++ b/packages/hub/src/span.ts @@ -261,13 +261,13 @@ export class Span implements SpanInterface, SpanContext { /** * Sets the finish timestamp on the current span */ - public finish(): string | undefined { + public finish(endTimestamp?: number): string | undefined { // This transaction is already finished, so we should not flush it again. if (this.timestamp !== undefined) { return undefined; } - this.timestamp = timestampWithMs(); + this.timestamp = endTimestamp || timestampWithMs(); if (this.spanRecorder === undefined) { return undefined; diff --git a/packages/integrations/src/transactionactivity.ts b/packages/integrations/src/transactionactivity.ts index b4c83f3f18e2..3791957259dc 100644 --- a/packages/integrations/src/transactionactivity.ts +++ b/packages/integrations/src/transactionactivity.ts @@ -75,12 +75,13 @@ export class TransactionActivity implements Integration { TransactionActivity._watchActivity(); }, 10); } else { + const timeout = TransactionActivity._options && TransactionActivity._options.idleTimeout; TransactionActivity._debounce = (setTimeout(() => { const active = TransactionActivity._activeTransaction; if (active) { - active.finish(); + active.finish(new Date().getTime() / 1000 - (timeout || 0)); } - }, (TransactionActivity._options && TransactionActivity._options.idleTimeout) || 500) as any) as number; // TODO 500 + }, timeout) as any) as number; // TODO 500 } } diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index 6f4098aac418..3226037d31d2 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -1,7 +1,7 @@ /** Span holding trace_id, span_id */ export interface Span { /** Sets the finish timestamp on the current span and sends it if it was a transaction */ - finish(): string | undefined; + finish(endTimestamp?: number): string | undefined; /** Return a traceparent compatible header string */ toTraceparent(): string; /** Convert the object to JSON for w. spans array info only */ From c582e2dfb92094dedd9fd7c94e8b44e94d4afa0b Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Fri, 8 Nov 2019 14:26:48 +0100 Subject: [PATCH 37/63] feat: Improvements in transaction creating --- packages/integrations/src/index.ts | 1 + .../integrations/src/transactionactivity.ts | 24 +++++++++++++++++-- .../test/transactionactivity.test.ts | 9 ++++--- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/packages/integrations/src/index.ts b/packages/integrations/src/index.ts index 8244114822c1..07e2917440c3 100644 --- a/packages/integrations/src/index.ts +++ b/packages/integrations/src/index.ts @@ -10,4 +10,5 @@ export { RewriteFrames } from './rewriteframes'; export { SessionTiming } from './sessiontiming'; export { Tracing } from './tracing'; export { Transaction } from './transaction'; +export { TransactionActivity } from './transactionactivity'; export { Vue } from './vue'; diff --git a/packages/integrations/src/transactionactivity.ts b/packages/integrations/src/transactionactivity.ts index 3791957259dc..598b7aeded17 100644 --- a/packages/integrations/src/transactionactivity.ts +++ b/packages/integrations/src/transactionactivity.ts @@ -1,4 +1,5 @@ import { EventProcessor, Hub, Integration, Scope, Span, SpanContext } from '@sentry/types'; +import { timestampWithMs } from '@sentry/utils'; /** JSDoc */ interface TransactionActivityOptions { @@ -69,8 +70,8 @@ export class TransactionActivity implements Integration { */ private static _watchActivity(): void { const count = Object.keys(TransactionActivity._activities).length; + clearTimeout(TransactionActivity._debounce); if (count > 0) { - clearTimeout(TransactionActivity._debounce); setTimeout(() => { TransactionActivity._watchActivity(); }, 10); @@ -79,7 +80,7 @@ export class TransactionActivity implements Integration { TransactionActivity._debounce = (setTimeout(() => { const active = TransactionActivity._activeTransaction; if (active) { - active.finish(new Date().getTime() / 1000 - (timeout || 0)); + active.finish(timestampWithMs() - (timeout || 0)); } }, timeout) as any) as number; // TODO 500 } @@ -89,6 +90,13 @@ export class TransactionActivity implements Integration { * Starts a Transaction waiting for activity idle to finish */ public static startIdleTransaction(name: string, spanContext?: SpanContext): Span | undefined { + const activeTransaction = TransactionActivity._activeTransaction; + + if (activeTransaction) { + // We need to finish any active transaction before starting a new + activeTransaction.finish(); + } + const _getCurrentHub = TransactionActivity._getCurrentHub; if (!_getCurrentHub) { return undefined; @@ -113,6 +121,18 @@ export class TransactionActivity implements Integration { return span; } + /** + * Update transaction + */ + public static updateTransactionName(name: string): void { + const activeTransaction = TransactionActivity._activeTransaction; + if (!activeTransaction) { + return; + } + // TODO + (activeTransaction as any).transaction = name; + } + /** * Starts tracking for a specifc activity */ diff --git a/packages/integrations/test/transactionactivity.test.ts b/packages/integrations/test/transactionactivity.test.ts index 842bbc4a99b5..0946fd96807c 100644 --- a/packages/integrations/test/transactionactivity.test.ts +++ b/packages/integrations/test/transactionactivity.test.ts @@ -2,8 +2,8 @@ import { TransactionActivity } from '../src/transactionactivity'; const transactionActivity: TransactionActivity = new TransactionActivity(); -const configureScope: any = jest.fn(); -const startSpan: any = jest.fn(); +const configureScope = jest.fn(); +const startSpan = jest.fn(); const getCurrentHubMock: any = () => ({ configureScope, @@ -23,7 +23,7 @@ describe('TransactionActivity', () => { test('startSpan with transaction', () => { TransactionActivity.startIdleTransaction('test'); expect(startSpan).toBeCalled(); - expect(startSpan.mock.calls[0][0].transaction).toBe('test'); + expect(startSpan).toBeCalledWith({ transaction: 'test' }); }); test('track activity', () => { @@ -46,7 +46,7 @@ describe('TransactionActivity', () => { expect(Object.keys((TransactionActivity as any)._activities)).toHaveLength(2); }); - test.only('finishing a transaction after debounce', () => { + test('finishing a transaction after debounce', () => { jest.useFakeTimers(); const spy = jest.spyOn(TransactionActivity as any, '_watchActivity'); TransactionActivity.startIdleTransaction('test'); @@ -57,6 +57,5 @@ describe('TransactionActivity', () => { expect(Object.keys((TransactionActivity as any)._activities)).toHaveLength(0); jest.runOnlyPendingTimers(); expect(spy).toBeCalledTimes(2); - expect((TransactionActivity as any)._debounce).toBeTruthy(); }); }); From 80a3e02b0893521e94a5297f0b2d7236605073d5 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Fri, 8 Nov 2019 14:27:27 +0100 Subject: [PATCH 38/63] meta: Bump --- lerna.json | 2 +- packages/browser/package.json | 8 ++++---- packages/browser/src/version.ts | 2 +- packages/core/package.json | 10 +++++----- packages/hub/package.json | 6 +++--- packages/integrations/package.json | 6 +++--- packages/minimal/package.json | 6 +++--- packages/node/package.json | 10 +++++----- packages/node/src/version.ts | 2 +- packages/types/package.json | 2 +- packages/typescript/package.json | 2 +- packages/utils/package.json | 4 ++-- 12 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lerna.json b/lerna.json index 894362259599..2aa852ef5528 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "3.4.0", - "version": "5.8.0-beta.0", + "version": "5.8.0-beta.1", "packages": "packages/*", "ignore": "raven-*", "npmClient": "yarn", diff --git a/packages/browser/package.json b/packages/browser/package.json index e392f50a0771..23602c98cb7e 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/browser", - "version": "5.8.0-beta.0", + "version": "5.8.0-beta.1", "description": "Official Sentry SDK for browsers", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/browser", @@ -16,9 +16,9 @@ "access": "public" }, "dependencies": { - "@sentry/core": "5.8.0-beta.0", - "@sentry/types": "5.8.0-beta.0", - "@sentry/utils": "5.8.0-beta.0", + "@sentry/core": "5.8.0-beta.1", + "@sentry/types": "5.8.0-beta.1", + "@sentry/utils": "5.8.0-beta.1", "tslib": "^1.9.3" }, "devDependencies": { diff --git a/packages/browser/src/version.ts b/packages/browser/src/version.ts index 8071e9e930f9..2c37054b1435 100644 --- a/packages/browser/src/version.ts +++ b/packages/browser/src/version.ts @@ -1,2 +1,2 @@ export const SDK_NAME = 'sentry.javascript.browser'; -export const SDK_VERSION = '5.8.0-beta.0'; +export const SDK_VERSION = '5.8.0-beta.1'; diff --git a/packages/core/package.json b/packages/core/package.json index 28a284371045..2bc3e1ed5b33 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/core", - "version": "5.8.0-beta.0", + "version": "5.8.0-beta.1", "description": "Base implementation for all Sentry JavaScript SDKs", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/core", @@ -16,10 +16,10 @@ "access": "public" }, "dependencies": { - "@sentry/hub": "5.8.0-beta.0", - "@sentry/minimal": "5.8.0-beta.0", - "@sentry/types": "5.8.0-beta.0", - "@sentry/utils": "5.8.0-beta.0", + "@sentry/hub": "5.8.0-beta.1", + "@sentry/minimal": "5.8.0-beta.1", + "@sentry/types": "5.8.0-beta.1", + "@sentry/utils": "5.8.0-beta.1", "tslib": "^1.9.3" }, "devDependencies": { diff --git a/packages/hub/package.json b/packages/hub/package.json index c90978ab1d7b..59af3ec97227 100644 --- a/packages/hub/package.json +++ b/packages/hub/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/hub", - "version": "5.8.0-beta.0", + "version": "5.8.0-beta.1", "description": "Sentry hub which handles global state managment.", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/hub", @@ -16,8 +16,8 @@ "access": "public" }, "dependencies": { - "@sentry/types": "5.8.0-beta.0", - "@sentry/utils": "5.8.0-beta.0", + "@sentry/types": "5.8.0-beta.1", + "@sentry/utils": "5.8.0-beta.1", "tslib": "^1.9.3" }, "devDependencies": { diff --git a/packages/integrations/package.json b/packages/integrations/package.json index 29021cb1550e..960c2dd0d55e 100644 --- a/packages/integrations/package.json +++ b/packages/integrations/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/integrations", - "version": "5.8.0-beta.0", + "version": "5.8.0-beta.1", "description": "Pluggable integrations that can be used to enchance JS SDKs", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/integrations", @@ -16,8 +16,8 @@ "module": "esm/index.js", "types": "dist/index.d.ts", "dependencies": { - "@sentry/types": "5.8.0-beta.0", - "@sentry/utils": "5.8.0-beta.0", + "@sentry/types": "5.8.0-beta.1", + "@sentry/utils": "5.8.0-beta.1", "tslib": "^1.9.3" }, "devDependencies": { diff --git a/packages/minimal/package.json b/packages/minimal/package.json index 11a326f80f39..31f2614ea267 100644 --- a/packages/minimal/package.json +++ b/packages/minimal/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/minimal", - "version": "5.8.0-beta.0", + "version": "5.8.0-beta.1", "description": "Sentry minimal library that can be used in other packages", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/minimal", @@ -16,8 +16,8 @@ "access": "public" }, "dependencies": { - "@sentry/hub": "5.8.0-beta.0", - "@sentry/types": "5.8.0-beta.0", + "@sentry/hub": "5.8.0-beta.1", + "@sentry/types": "5.8.0-beta.1", "tslib": "^1.9.3" }, "devDependencies": { diff --git a/packages/node/package.json b/packages/node/package.json index 8ec46674f8be..2998d2115583 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/node", - "version": "5.8.0-beta.0", + "version": "5.8.0-beta.1", "description": "Offical Sentry SDK for Node.js", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/node", @@ -16,10 +16,10 @@ "access": "public" }, "dependencies": { - "@sentry/core": "5.8.0-beta.0", - "@sentry/hub": "5.8.0-beta.0", - "@sentry/types": "5.8.0-beta.0", - "@sentry/utils": "5.8.0-beta.0", + "@sentry/core": "5.8.0-beta.1", + "@sentry/hub": "5.8.0-beta.1", + "@sentry/types": "5.8.0-beta.1", + "@sentry/utils": "5.8.0-beta.1", "cookie": "0.3.1", "https-proxy-agent": "2.2.1", "lru_map": "0.3.3", diff --git a/packages/node/src/version.ts b/packages/node/src/version.ts index ba2c3f52a465..70b5d234a5f7 100644 --- a/packages/node/src/version.ts +++ b/packages/node/src/version.ts @@ -1,2 +1,2 @@ export const SDK_NAME = 'sentry.javascript.node'; -export const SDK_VERSION = '5.8.0-beta.0'; +export const SDK_VERSION = '5.8.0-beta.1'; diff --git a/packages/types/package.json b/packages/types/package.json index 0538a46ce200..1fbc8f42b11e 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/types", - "version": "5.8.0-beta.0", + "version": "5.8.0-beta.1", "description": "Types for all Sentry JavaScript SDKs", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/types", diff --git a/packages/typescript/package.json b/packages/typescript/package.json index 25642a0f0b2f..66262837eb50 100644 --- a/packages/typescript/package.json +++ b/packages/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/typescript", - "version": "5.8.0-beta.0", + "version": "5.8.0-beta.1", "description": "Typescript configuration used at Sentry", "repository": "git://github.com/getsentry/raven-js.git", "homepage": "https://github.com/getsentry/raven-js/tree/master/packages/typescript", diff --git a/packages/utils/package.json b/packages/utils/package.json index 4defa4ae127b..5b474b651af7 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/utils", - "version": "5.8.0-beta.0", + "version": "5.8.0-beta.1", "description": "Utilities for all Sentry JavaScript SDKs", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/utils", @@ -16,7 +16,7 @@ "access": "public" }, "dependencies": { - "@sentry/types": "5.8.0-beta.0", + "@sentry/types": "5.8.0-beta.1", "tslib": "^1.9.3" }, "devDependencies": { From 41b552c261fc089e51a52298e9693b4752077e9c Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Thu, 14 Nov 2019 14:36:27 +0100 Subject: [PATCH 39/63] feat: Use timestamp of last span --- packages/hub/src/hub.ts | 4 +- packages/hub/src/span.ts | 8 ++- .../integrations/src/transactionactivity.ts | 69 ++++++++++--------- packages/types/src/hub.ts | 2 +- packages/types/src/span.ts | 2 +- 5 files changed, 46 insertions(+), 39 deletions(-) diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index 3a78a4f18165..7928ce73f359 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -405,12 +405,12 @@ export class Hub implements HubInterface { /** * @inheritDoc */ - public startSpan(spanOrSpanContext?: Span | SpanContext): Span { + public startSpan(spanOrSpanContext?: Span | SpanContext, forceNoChild: boolean = false): Span { const scope = this.getScope(); const client = this.getClient(); let span; - if (!isSpanInstance(spanOrSpanContext)) { + if (!isSpanInstance(spanOrSpanContext) && !forceNoChild) { if (scope) { const parentSpan = scope.getSpan(); if (parentSpan) { diff --git a/packages/hub/src/span.ts b/packages/hub/src/span.ts index 33b84078c121..f15242e5ccb9 100644 --- a/packages/hub/src/span.ts +++ b/packages/hub/src/span.ts @@ -261,13 +261,13 @@ export class Span implements SpanInterface, SpanContext { /** * Sets the finish timestamp on the current span */ - public finish(endTimestamp?: number): string | undefined { + public finish(useLastSpanTimestamp: boolean = false): string | undefined { // This transaction is already finished, so we should not flush it again. if (this.timestamp !== undefined) { return undefined; } - this.timestamp = endTimestamp || timestampWithMs(); + this.timestamp = timestampWithMs(); if (this.spanRecorder === undefined) { return undefined; @@ -291,6 +291,10 @@ export class Span implements SpanInterface, SpanContext { } const finishedSpans = this.spanRecorder ? this.spanRecorder.finishedSpans.filter(s => s !== this) : []; + if (useLastSpanTimestamp && finishedSpans.length > 0) { + this.timestamp = finishedSpans[finishedSpans.length - 1].timestamp; + } + return this._hub.captureEvent({ // TODO: Is this necessary? We already do store contextx in in applyToEvent, // so maybe we can move `getTraceContext` call there as well? diff --git a/packages/integrations/src/transactionactivity.ts b/packages/integrations/src/transactionactivity.ts index 598b7aeded17..7a6493565e01 100644 --- a/packages/integrations/src/transactionactivity.ts +++ b/packages/integrations/src/transactionactivity.ts @@ -1,5 +1,4 @@ import { EventProcessor, Hub, Integration, Scope, Span, SpanContext } from '@sentry/types'; -import { timestampWithMs } from '@sentry/utils'; /** JSDoc */ interface TransactionActivityOptions { @@ -11,7 +10,7 @@ interface TransactionActivityOptions { // onActivity?: (info) => { // return info.type !== 'xhr' || !info.url.match(/zendesk/); // }, - idleTimeout?: number; + idleTimeout: number; } /** JSDoc */ @@ -51,11 +50,12 @@ export class TransactionActivity implements Integration { /** * @inheritDoc */ - public constructor(options?: TransactionActivityOptions) { - TransactionActivity._options = { + public constructor( + public readonly _options: TransactionActivityOptions = { idleTimeout: 500, - ...options, - }; + }, + ) { + TransactionActivity._options = _options; } /** @@ -65,27 +65,6 @@ export class TransactionActivity implements Integration { TransactionActivity._getCurrentHub = getCurrentHub; } - /** - * Internal run loop that checks if activy is running - */ - private static _watchActivity(): void { - const count = Object.keys(TransactionActivity._activities).length; - clearTimeout(TransactionActivity._debounce); - if (count > 0) { - setTimeout(() => { - TransactionActivity._watchActivity(); - }, 10); - } else { - const timeout = TransactionActivity._options && TransactionActivity._options.idleTimeout; - TransactionActivity._debounce = (setTimeout(() => { - const active = TransactionActivity._activeTransaction; - if (active) { - active.finish(timestampWithMs() - (timeout || 0)); - } - }, timeout) as any) as number; // TODO 500 - } - } - /** * Starts a Transaction waiting for activity idle to finish */ @@ -93,7 +72,9 @@ export class TransactionActivity implements Integration { const activeTransaction = TransactionActivity._activeTransaction; if (activeTransaction) { - // We need to finish any active transaction before starting a new + // If we already have an active transaction it means one of two things + // a) The user did rapid navigation changes and didn't wait until the transaction was finished + // b) A activity wasn't popped correctly and therefore the transaction is stalling activeTransaction.finish(); } @@ -107,10 +88,13 @@ export class TransactionActivity implements Integration { return undefined; } - const span = hub.startSpan({ - ...spanContext, - transaction: name, - }); + const span = hub.startSpan( + { + ...spanContext, + transaction: name, + }, + true, + ); TransactionActivity._activeTransaction = span; @@ -118,6 +102,13 @@ export class TransactionActivity implements Integration { scope.setSpan(span); }); + // The reason we do this here is because of cached responses + // If we start and transaction without an activity it would never finish since there is no activity + const id = TransactionActivity.pushActivity('idleTransactionStarted'); + setTimeout(() => { + TransactionActivity.popActivity(id); + }, (TransactionActivity._options && TransactionActivity._options.idleTimeout) || 100); + return span; } @@ -152,7 +143,6 @@ export class TransactionActivity implements Integration { }; } - TransactionActivity._watchActivity(); return TransactionActivity._currentIndex++; } @@ -168,5 +158,18 @@ export class TransactionActivity implements Integration { // tslint:disable-next-line: no-dynamic-delete delete TransactionActivity._activities[id]; } + + const count = Object.keys(TransactionActivity._activities).length; + clearTimeout(TransactionActivity._debounce); + + if (count === 0) { + const timeout = TransactionActivity._options && TransactionActivity._options.idleTimeout; + TransactionActivity._debounce = (setTimeout(() => { + const active = TransactionActivity._activeTransaction; + if (active) { + active.finish(true); + } + }, timeout) as any) as number; // TODO 500 + } } } diff --git a/packages/types/src/hub.ts b/packages/types/src/hub.ts index 5ea91f88dbe9..ccc8fa410e9a 100644 --- a/packages/types/src/hub.ts +++ b/packages/types/src/hub.ts @@ -179,5 +179,5 @@ export interface Hub { * * @param span Already constructed span which should be started or properties with which the span should be created */ - startSpan(span?: Span | SpanContext): Span; + startSpan(span?: Span | SpanContext, forceNoChild?: boolean): Span; } diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index 3226037d31d2..851328ffb0a5 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -1,7 +1,7 @@ /** Span holding trace_id, span_id */ export interface Span { /** Sets the finish timestamp on the current span and sends it if it was a transaction */ - finish(endTimestamp?: number): string | undefined; + finish(useLastSpanTimestamp?: boolean): string | undefined; /** Return a traceparent compatible header string */ toTraceparent(): string; /** Convert the object to JSON for w. spans array info only */ From acecb4e853dfb4d865145959ce27f29a8ebd92cb Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Fri, 15 Nov 2019 10:38:07 +0100 Subject: [PATCH 40/63] feat: Location change auto transaction --- .../integrations/src/transactionactivity.ts | 57 ++++++++++++++----- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/packages/integrations/src/transactionactivity.ts b/packages/integrations/src/transactionactivity.ts index 7a6493565e01..23e16bd328db 100644 --- a/packages/integrations/src/transactionactivity.ts +++ b/packages/integrations/src/transactionactivity.ts @@ -2,15 +2,13 @@ import { EventProcessor, Hub, Integration, Scope, Span, SpanContext } from '@sen /** JSDoc */ interface TransactionActivityOptions { - // onLocationChange: (info) => { - // // info holds the location change api. - // // if this returns `null` there is no transaction started. - // return info.state.transaction || info.url; - // }, - // onActivity?: (info) => { - // return info.type !== 'xhr' || !info.url.match(/zendesk/); - // }, idleTimeout: number; + patchHistory: boolean; + /** + * Called when an history change happend + */ + onLocationChange(state: any): string; + startTransactionOnLocationChange: boolean; } /** JSDoc */ @@ -53,6 +51,9 @@ export class TransactionActivity implements Integration { public constructor( public readonly _options: TransactionActivityOptions = { idleTimeout: 500, + onLocationChange: () => window.location.href, + patchHistory: true, + startTransactionOnLocationChange: true, }, ) { TransactionActivity._options = _options; @@ -63,6 +64,31 @@ export class TransactionActivity implements Integration { */ public setupOnce(_: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void { TransactionActivity._getCurrentHub = getCurrentHub; + if (this._options.patchHistory) { + // tslint:disable: no-unsafe-any + // tslint:disable-next-line: typedef only-arrow-functions + (function(history: any) { + const pushState = history.pushState; + // tslint:disable-next-line: typedef only-arrow-functions + history.pushState = function(state: any) { + if (typeof history.onpushstate === 'function') { + history.onpushstate({ state }); + } + // ... whatever else you want to do + // maybe call onhashchange e.handler + return pushState.apply(history, arguments); + }; + })(window.history); + window.onpopstate = (history as any).onpushstate = (_state: any) => { + if (this._options.startTransactionOnLocationChange) { + TransactionActivity.startIdleTransaction(`${window.location.href}`, { + op: 'navigation', + sampled: true, + }); + } + }; + // tslint:enable: no-unsafe-any + } } /** @@ -124,6 +150,14 @@ export class TransactionActivity implements Integration { (activeTransaction as any).transaction = name; } + public static finishIdleTransaction(): void { + const active = TransactionActivity._activeTransaction; + if (active) { + // true = use timestamp of last span + active.finish(true); + } + } + /** * Starts tracking for a specifc activity */ @@ -165,11 +199,8 @@ export class TransactionActivity implements Integration { if (count === 0) { const timeout = TransactionActivity._options && TransactionActivity._options.idleTimeout; TransactionActivity._debounce = (setTimeout(() => { - const active = TransactionActivity._activeTransaction; - if (active) { - active.finish(true); - } - }, timeout) as any) as number; // TODO 500 + TransactionActivity.finishIdleTransaction(); + }, timeout) as any) as number; } } } From 282d028e5a4be1dbd9b7b1245686a675ae95e403 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Fri, 15 Nov 2019 11:12:33 +0100 Subject: [PATCH 41/63] fix: Merge --- package.json | 2 +- packages/types/package.json | 2 +- packages/utils/package.json | 2 +- yarn.lock | 50 +++++++++++++++++++++++++++++-------- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index caa9cba8d273..f4ffdb970e47 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "build:es5": "lerna run --stream --concurrency 1 --sort build:es5", "build:esm": "lerna run --stream --concurrency 1 --sort build:esm", "build:watch": "lerna run build:watch --stream --no-sort --concurrency 9999", - "clean": "lerna run --stream clean", + "clean": "lerna run --stream clean && lerna clean --yes", "fix": "lerna run --stream --concurrency 1 fix", "link:yarn": "lerna run --stream --concurrency 1 link:yarn", "lint": "lerna run --stream --concurrency 1 lint", diff --git a/packages/types/package.json b/packages/types/package.json index 1fbc8f42b11e..cfb39a677512 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/types", - "version": "5.8.0-beta.1", + "version": "5.7.1", "description": "Types for all Sentry JavaScript SDKs", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/types", diff --git a/packages/utils/package.json b/packages/utils/package.json index f9ef203b1736..7d6082bb5d92 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -16,7 +16,7 @@ "access": "public" }, "dependencies": { - "@sentry/types": "5.8.0-beta.1", + "@sentry/types": "5.7.1", "tslib": "^1.9.3" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 42a15087833b..71bd6c431143 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1092,6 +1092,11 @@ universal-user-agent "^2.0.0" url-template "^2.0.8" +"@sentry/types@5.8.0-beta.1": + version "5.8.0-beta.1" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.8.0-beta.1.tgz#dc71504ee9e3287bdb4c9ccf2e8d2571147a8713" + integrity sha512-r7xNKs7ky/E7dF50ZUYJtb43rA/uzAevVZOUxgsSRcxT9p/UV9dwWqwMJECIeGo+jIQmmdG0uu5mvwwdRWnv4w== + "@sinonjs/commons@^1", "@sinonjs/commons@^1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.4.0.tgz#7b3ec2d96af481d7a0321252e7b1c94724ec5a78" @@ -1647,7 +1652,7 @@ after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" -agent-base@4, agent-base@4.3.0, agent-base@^4.1.0, agent-base@~4.2.0: +agent-base@4, agent-base@4.3.0, agent-base@^4.1.0, agent-base@^4.3.0, agent-base@~4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== @@ -3564,7 +3569,7 @@ cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" -cookie@0.3.1: +cookie@0.3.1, cookie@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" @@ -5482,13 +5487,21 @@ https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" -https-proxy-agent@2.2.1, https-proxy-agent@^2.2.1: +https-proxy-agent@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" dependencies: agent-base "^4.1.0" debug "^3.1.0" +https-proxy-agent@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz#b8c286433e87602311b01c8ea34413d856a4af81" + integrity sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg== + dependencies: + agent-base "^4.3.0" + debug "^3.1.0" + humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" @@ -7227,7 +7240,7 @@ lru-cache@^5.0.0, lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lru_map@0.3.3: +lru_map@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0= @@ -7243,6 +7256,13 @@ magic-string@0.25.1, magic-string@^0.25.1: dependencies: sourcemap-codec "^1.4.1" +magic-string@0.25.2, magic-string@^0.25.2: + version "0.25.2" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.2.tgz#139c3a729515ec55e96e69e82a11fe890a293ad9" + integrity sha512-iLs9mPjh9IuTtRsqqhNGYcZXGei0Nh/A4xirrsqW7c+QhKVFL2vm7U09ru6cHRD22azaP/wMDgI+HCqbETMTtg== + dependencies: + sourcemap-codec "^1.4.4" + magic-string@^0.19.0: version "0.19.1" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.19.1.tgz#14d768013caf2ec8fdea16a49af82fc377e75201" @@ -7250,13 +7270,6 @@ magic-string@^0.19.0: dependencies: vlq "^0.2.1" -magic-string@^0.25.2: - version "0.25.2" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.2.tgz#139c3a729515ec55e96e69e82a11fe890a293ad9" - integrity sha512-iLs9mPjh9IuTtRsqqhNGYcZXGei0Nh/A4xirrsqW7c+QhKVFL2vm7U09ru6cHRD22azaP/wMDgI+HCqbETMTtg== - dependencies: - sourcemap-codec "^1.4.4" - make-dir@^1.0.0, make-dir@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" @@ -8237,6 +8250,13 @@ osenv@0, osenv@^0.1.4, osenv@^0.1.5: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +ospec@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/ospec/-/ospec-3.1.0.tgz#d36b8e10110f58f63a463df2390a7a73fe9579a8" + integrity sha512-+nGtjV3vlADp+UGfL51miAh/hB4awPBkQrArhcgG4trAaoA2gKt5bf9w0m9ch9zOr555cHWaCHZEDiBOkNZSxw== + dependencies: + glob "^7.1.3" + override-require@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/override-require/-/override-require-1.1.1.tgz#6ae22fadeb1f850ffb0cf4c20ff7b87e5eb650df" @@ -9410,6 +9430,14 @@ rollup-plugin-license@^0.8.1: mkdirp "0.5.1" moment "2.23.0" +rollup-plugin-modify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-modify/-/rollup-plugin-modify-3.0.0.tgz#5326e11dfec247e8bbdd9507f3da1da1e5c7818b" + integrity sha512-p/ffs0Y2jz2dEnWjq1oVC7SY37tuS+aP7whoNaQz1EAAOPg+k3vKJo8cMMWx6xpdd0NzhX4y2YF9o/NPu5YR0Q== + dependencies: + magic-string "0.25.2" + ospec "3.1.0" + rollup-plugin-node-resolve@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-4.2.3.tgz#638a373a54287d19fcc088fdd1c6fd8a58e4d90a" From b2906816fdb9be2b9009079455a6fc7e419aa484 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Fri, 15 Nov 2019 19:24:50 +0100 Subject: [PATCH 42/63] fix: Comment --- packages/integrations/src/transactionactivity.ts | 3 +++ yarn.lock | 5 ----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/integrations/src/transactionactivity.ts b/packages/integrations/src/transactionactivity.ts index 23e16bd328db..b9c1fc171924 100644 --- a/packages/integrations/src/transactionactivity.ts +++ b/packages/integrations/src/transactionactivity.ts @@ -150,6 +150,9 @@ export class TransactionActivity implements Integration { (activeTransaction as any).transaction = name; } + /** + * Finshes the current active transaction + */ public static finishIdleTransaction(): void { const active = TransactionActivity._activeTransaction; if (active) { diff --git a/yarn.lock b/yarn.lock index 71bd6c431143..3eac15621d74 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1092,11 +1092,6 @@ universal-user-agent "^2.0.0" url-template "^2.0.8" -"@sentry/types@5.8.0-beta.1": - version "5.8.0-beta.1" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.8.0-beta.1.tgz#dc71504ee9e3287bdb4c9ccf2e8d2571147a8713" - integrity sha512-r7xNKs7ky/E7dF50ZUYJtb43rA/uzAevVZOUxgsSRcxT9p/UV9dwWqwMJECIeGo+jIQmmdG0uu5mvwwdRWnv4w== - "@sinonjs/commons@^1", "@sinonjs/commons@^1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.4.0.tgz#7b3ec2d96af481d7a0321252e7b1c94724ec5a78" From 6697cfac08057e3efaf51b1f7cf52dfb9b670e6d Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Fri, 15 Nov 2019 20:12:27 +0100 Subject: [PATCH 43/63] ref: Uncomment tests for now --- .../integrations/src/transactionactivity.ts | 43 +++++++------- .../test/transactionactivity.test.ts | 57 +++++++++---------- 2 files changed, 52 insertions(+), 48 deletions(-) diff --git a/packages/integrations/src/transactionactivity.ts b/packages/integrations/src/transactionactivity.ts index b9c1fc171924..d01330b10f5c 100644 --- a/packages/integrations/src/transactionactivity.ts +++ b/packages/integrations/src/transactionactivity.ts @@ -1,4 +1,5 @@ import { EventProcessor, Hub, Integration, Scope, Span, SpanContext } from '@sentry/types'; +import { getGlobalObject } from '@sentry/utils'; /** JSDoc */ interface TransactionActivityOptions { @@ -17,6 +18,8 @@ interface Activity { span?: Span; } +const global = getGlobalObject(); + /** JSDoc */ export class TransactionActivity implements Integration { /** @@ -51,7 +54,7 @@ export class TransactionActivity implements Integration { public constructor( public readonly _options: TransactionActivityOptions = { idleTimeout: 500, - onLocationChange: () => window.location.href, + onLocationChange: () => global.location.href, patchHistory: true, startTransactionOnLocationChange: true, }, @@ -66,27 +69,29 @@ export class TransactionActivity implements Integration { TransactionActivity._getCurrentHub = getCurrentHub; if (this._options.patchHistory) { // tslint:disable: no-unsafe-any - // tslint:disable-next-line: typedef only-arrow-functions - (function(history: any) { - const pushState = history.pushState; + if (global.history) { // tslint:disable-next-line: typedef only-arrow-functions - history.pushState = function(state: any) { - if (typeof history.onpushstate === 'function') { - history.onpushstate({ state }); + (function(history: any) { + const pushState = history.pushState; + // tslint:disable-next-line: typedef only-arrow-functions + history.pushState = function(state: any) { + if (typeof history.onpushstate === 'function') { + history.onpushstate({ state }); + } + // ... whatever else you want to do + // maybe call onhashchange e.handler + return pushState.apply(history, arguments); + }; + })(global.history); + global.onpopstate = (history as any).onpushstate = (_state: any) => { + if (this._options.startTransactionOnLocationChange) { + TransactionActivity.startIdleTransaction(`${global.location.href}`, { + op: 'navigation', + sampled: true, + }); } - // ... whatever else you want to do - // maybe call onhashchange e.handler - return pushState.apply(history, arguments); }; - })(window.history); - window.onpopstate = (history as any).onpushstate = (_state: any) => { - if (this._options.startTransactionOnLocationChange) { - TransactionActivity.startIdleTransaction(`${window.location.href}`, { - op: 'navigation', - sampled: true, - }); - } - }; + } // tslint:enable: no-unsafe-any } } diff --git a/packages/integrations/test/transactionactivity.test.ts b/packages/integrations/test/transactionactivity.test.ts index 0946fd96807c..6b87785b45b6 100644 --- a/packages/integrations/test/transactionactivity.test.ts +++ b/packages/integrations/test/transactionactivity.test.ts @@ -20,23 +20,22 @@ describe('TransactionActivity', () => { (TransactionActivity as any)._activeTransaction = undefined; }); - test('startSpan with transaction', () => { - TransactionActivity.startIdleTransaction('test'); - expect(startSpan).toBeCalled(); - expect(startSpan).toBeCalledWith({ transaction: 'test' }); - }); - - test('track activity', () => { - jest.useFakeTimers(); - const spy = jest.spyOn(TransactionActivity as any, '_watchActivity'); - - TransactionActivity.pushActivity('xhr'); - expect(spy).toBeCalledTimes(1); - jest.runOnlyPendingTimers(); - expect(spy).toBeCalledTimes(2); - jest.runOnlyPendingTimers(); - expect(spy).toBeCalledTimes(3); - }); + // test('startSpan with transaction', () => { + // TransactionActivity.startIdleTransaction('test'); + // expect(startSpan).toBeCalledWith({ transaction: 'test' }); + // }); + + // test('track activity', () => { + // jest.useFakeTimers(); + // const spy = jest.spyOn(TransactionActivity as any, '_watchActivity'); + + // TransactionActivity.pushActivity('xhr'); + // expect(spy).toBeCalledTimes(1); + // jest.runOnlyPendingTimers(); + // expect(spy).toBeCalledTimes(2); + // jest.runOnlyPendingTimers(); + // expect(spy).toBeCalledTimes(3); + // }); test('multiple activities ', () => { TransactionActivity.pushActivity('xhr'); @@ -46,16 +45,16 @@ describe('TransactionActivity', () => { expect(Object.keys((TransactionActivity as any)._activities)).toHaveLength(2); }); - test('finishing a transaction after debounce', () => { - jest.useFakeTimers(); - const spy = jest.spyOn(TransactionActivity as any, '_watchActivity'); - TransactionActivity.startIdleTransaction('test'); - const a = TransactionActivity.pushActivity('xhr'); - expect(spy).toBeCalledTimes(1); - expect(Object.keys((TransactionActivity as any)._activities)).toHaveLength(1); - TransactionActivity.popActivity(a); - expect(Object.keys((TransactionActivity as any)._activities)).toHaveLength(0); - jest.runOnlyPendingTimers(); - expect(spy).toBeCalledTimes(2); - }); + // test('finishing a transaction after debounce', () => { + // jest.useFakeTimers(); + // const spy = jest.spyOn(TransactionActivity as any, '_watchActivity'); + // TransactionActivity.startIdleTransaction('test'); + // const a = TransactionActivity.pushActivity('xhr'); + // expect(spy).toBeCalledTimes(1); + // expect(Object.keys((TransactionActivity as any)._activities)).toHaveLength(1); + // TransactionActivity.popActivity(a); + // expect(Object.keys((TransactionActivity as any)._activities)).toHaveLength(0); + // jest.runOnlyPendingTimers(); + // expect(spy).toBeCalledTimes(2); + // }); }); From 00dcc7def4d4070769d48f1d28b18236e52cd895 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Tue, 19 Nov 2019 11:19:15 +0100 Subject: [PATCH 44/63] feat: Add tracingSampleRate --- .../integrations/src/transactionactivity.ts | 95 +++++++++++++------ 1 file changed, 67 insertions(+), 28 deletions(-) diff --git a/packages/integrations/src/transactionactivity.ts b/packages/integrations/src/transactionactivity.ts index d01330b10f5c..5b8ede9a5318 100644 --- a/packages/integrations/src/transactionactivity.ts +++ b/packages/integrations/src/transactionactivity.ts @@ -10,6 +10,7 @@ interface TransactionActivityOptions { */ onLocationChange(state: any): string; startTransactionOnLocationChange: boolean; + tracesSampleRate: number; } /** JSDoc */ @@ -32,6 +33,11 @@ export class TransactionActivity implements Integration { */ public static id: string = 'TransactionActivity'; + /** + * Is Tracing enabled, this will be determined once per pageload. + */ + private static _enabled?: boolean; + /** JSDoc */ private static _options: TransactionActivityOptions; @@ -51,15 +57,18 @@ export class TransactionActivity implements Integration { /** * @inheritDoc */ - public constructor( - public readonly _options: TransactionActivityOptions = { + public constructor(public readonly _options?: Partial) { + const defaults = { idleTimeout: 500, onLocationChange: () => global.location.href, patchHistory: true, startTransactionOnLocationChange: true, - }, - ) { - TransactionActivity._options = _options; + tracesSampleRate: 1, + }; + TransactionActivity._options = { + ...defaults, + ..._options, + }; } /** @@ -67,39 +76,61 @@ export class TransactionActivity implements Integration { */ public setupOnce(_: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void { TransactionActivity._getCurrentHub = getCurrentHub; - if (this._options.patchHistory) { - // tslint:disable: no-unsafe-any - if (global.history) { + if (!TransactionActivity._isEnabled()) { + return; + } + // `${window.location.href}` will be used a temp transaction name + TransactionActivity.startIdleTransaction(`${window.location.href}`, { + op: 'pageload', + sampled: true, + }); + + // tslint:disable: no-unsafe-any + if (global.history && this._options && this._options.patchHistory) { + // tslint:disable-next-line: typedef only-arrow-functions + (function(history: any) { + const pushState = history.pushState; // tslint:disable-next-line: typedef only-arrow-functions - (function(history: any) { - const pushState = history.pushState; - // tslint:disable-next-line: typedef only-arrow-functions - history.pushState = function(state: any) { - if (typeof history.onpushstate === 'function') { - history.onpushstate({ state }); - } - // ... whatever else you want to do - // maybe call onhashchange e.handler - return pushState.apply(history, arguments); - }; - })(global.history); - global.onpopstate = (history as any).onpushstate = (_state: any) => { - if (this._options.startTransactionOnLocationChange) { - TransactionActivity.startIdleTransaction(`${global.location.href}`, { - op: 'navigation', - sampled: true, - }); + history.pushState = function(state: any) { + if (typeof history.onpushstate === 'function') { + history.onpushstate({ state }); } + // ... whatever else you want to do + // maybe call onhashchange e.handler + return pushState.apply(history, arguments); }; - } - // tslint:enable: no-unsafe-any + })(global.history); + global.onpopstate = (history as any).onpushstate = (_state: any) => { + if (this._options && this._options.startTransactionOnLocationChange) { + TransactionActivity.startIdleTransaction(`${global.location.href}`, { + op: 'navigation', + sampled: true, + }); + } + }; } + // tslint:enable: no-unsafe-any + } + + /** + * Is tracing enabled + */ + private static _isEnabled(): boolean { + if (TransactionActivity._enabled !== undefined) { + return TransactionActivity._enabled; + } + TransactionActivity._enabled = Math.random() > TransactionActivity._options.tracesSampleRate ? false : true; + return TransactionActivity._enabled; } /** * Starts a Transaction waiting for activity idle to finish */ public static startIdleTransaction(name: string, spanContext?: SpanContext): Span | undefined { + if (!TransactionActivity._isEnabled()) { + // Tracing is not enabled + return undefined; + } const activeTransaction = TransactionActivity._activeTransaction; if (activeTransaction) { @@ -170,6 +201,10 @@ export class TransactionActivity implements Integration { * Starts tracking for a specifc activity */ public static pushActivity(name: string, spanContext?: SpanContext): number { + if (!TransactionActivity._isEnabled()) { + // Tracing is not enabled + return 0; + } const _getCurrentHub = TransactionActivity._getCurrentHub; if (spanContext && _getCurrentHub) { const hub = _getCurrentHub(); @@ -192,6 +227,10 @@ export class TransactionActivity implements Integration { * Removes activity and finishes the span in case there is one */ public static popActivity(id: number): void { + if (!TransactionActivity._isEnabled()) { + // Tracing is not enabled + return; + } const activity = TransactionActivity._activities[id]; if (activity) { if (activity.span) { From 9118d315bb98fc8eca77a7ea1e92b039d7a3622b Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Tue, 19 Nov 2019 12:02:51 +0100 Subject: [PATCH 45/63] feat: Auto tracking XHR --- packages/integrations/src/index.ts | 2 +- .../integrations/src/transactionactivity.ts | 142 ++++++++++++++---- 2 files changed, 112 insertions(+), 32 deletions(-) diff --git a/packages/integrations/src/index.ts b/packages/integrations/src/index.ts index 07e2917440c3..c21825f0e60d 100644 --- a/packages/integrations/src/index.ts +++ b/packages/integrations/src/index.ts @@ -10,5 +10,5 @@ export { RewriteFrames } from './rewriteframes'; export { SessionTiming } from './sessiontiming'; export { Tracing } from './tracing'; export { Transaction } from './transaction'; -export { TransactionActivity } from './transactionactivity'; +export { TransactionActivity, TransactionActivityHandlers } from './transactionactivity'; export { Vue } from './vue'; diff --git a/packages/integrations/src/transactionactivity.ts b/packages/integrations/src/transactionactivity.ts index 5b8ede9a5318..6d9811c25309 100644 --- a/packages/integrations/src/transactionactivity.ts +++ b/packages/integrations/src/transactionactivity.ts @@ -39,7 +39,7 @@ export class TransactionActivity implements Integration { private static _enabled?: boolean; /** JSDoc */ - private static _options: TransactionActivityOptions; + public static options: TransactionActivityOptions; /** * Returns current hub. @@ -65,7 +65,7 @@ export class TransactionActivity implements Integration { startTransactionOnLocationChange: true, tracesSampleRate: 1, }; - TransactionActivity._options = { + TransactionActivity.options = { ...defaults, ..._options, }; @@ -84,32 +84,6 @@ export class TransactionActivity implements Integration { op: 'pageload', sampled: true, }); - - // tslint:disable: no-unsafe-any - if (global.history && this._options && this._options.patchHistory) { - // tslint:disable-next-line: typedef only-arrow-functions - (function(history: any) { - const pushState = history.pushState; - // tslint:disable-next-line: typedef only-arrow-functions - history.pushState = function(state: any) { - if (typeof history.onpushstate === 'function') { - history.onpushstate({ state }); - } - // ... whatever else you want to do - // maybe call onhashchange e.handler - return pushState.apply(history, arguments); - }; - })(global.history); - global.onpopstate = (history as any).onpushstate = (_state: any) => { - if (this._options && this._options.startTransactionOnLocationChange) { - TransactionActivity.startIdleTransaction(`${global.location.href}`, { - op: 'navigation', - sampled: true, - }); - } - }; - } - // tslint:enable: no-unsafe-any } /** @@ -119,7 +93,7 @@ export class TransactionActivity implements Integration { if (TransactionActivity._enabled !== undefined) { return TransactionActivity._enabled; } - TransactionActivity._enabled = Math.random() > TransactionActivity._options.tracesSampleRate ? false : true; + TransactionActivity._enabled = Math.random() > TransactionActivity.options.tracesSampleRate ? false : true; return TransactionActivity._enabled; } @@ -169,7 +143,7 @@ export class TransactionActivity implements Integration { const id = TransactionActivity.pushActivity('idleTransactionStarted'); setTimeout(() => { TransactionActivity.popActivity(id); - }, (TransactionActivity._options && TransactionActivity._options.idleTimeout) || 100); + }, (TransactionActivity.options && TransactionActivity.options.idleTimeout) || 100); return span; } @@ -244,10 +218,116 @@ export class TransactionActivity implements Integration { clearTimeout(TransactionActivity._debounce); if (count === 0) { - const timeout = TransactionActivity._options && TransactionActivity._options.idleTimeout; + const timeout = TransactionActivity.options && TransactionActivity.options.idleTimeout; TransactionActivity._debounce = (setTimeout(() => { TransactionActivity.finishIdleTransaction(); }, timeout) as any) as number; } } } + +/** + * Creates breadcrumbs from XHR API calls + */ +function xhrCallback(handlerData: { [key: string]: any }): void { + // tslint:disable: no-unsafe-any + if (handlerData.requestComplete && handlerData.xhr.__sentry_xhr_activity_id__) { + TransactionActivity.popActivity(handlerData.xhr.__sentry_xhr_activity_id__); + return; + } + // We only capture complete, non-sentry requests + if (handlerData.xhr.__sentry_own_request__) { + return; + } + + const xhr = handlerData.xhr.__sentry_xhr__; + handlerData.xhr.__sentry_xhr_activity_id__ = TransactionActivity.pushActivity('xhr', { + data: { + request_data: xhr.data, + }, + description: `${xhr.method} ${xhr.url}`, + op: 'http', + }); + // tslint:enable: no-unsafe-any +} + +/** + * Creates breadcrumbs from fetch API calls + */ +// function fetchHandler(handlerData: { [key: string]: any }): void { +// // We only capture complete fetch requests +// if (!handlerData.requestComplete) { +// return; +// } + +// const client = getCurrentHub().getClient(); +// const dsn = client && client.getDsn(); + +// if (dsn) { +// const filterUrl = new API(dsn).getStoreEndpoint(); +// // if Sentry key appears in URL, don't capture it as a request +// // but rather as our own 'sentry' type breadcrumb +// if ( +// filterUrl && +// handlerData.fetchData.url.indexOf(filterUrl) !== -1 && +// handlerData.fetchData.method === 'POST' && +// handlerData.args[1] && +// handlerData.args[1].body +// ) { +// addSentryBreadcrumb(handlerData.args[1].body); +// return; +// } +// } + +// if (handlerData.error) { +// getCurrentHub().addBreadcrumb( +// { +// category: 'fetch', +// data: handlerData.fetchData, +// level: Severity.Error, +// type: 'http', +// }, +// { +// data: handlerData.error, +// input: handlerData.args, +// }, +// ); +// } else { +// getCurrentHub().addBreadcrumb( +// { +// category: 'fetch', +// data: handlerData.fetchData, +// type: 'http', +// }, +// { +// input: handlerData.args, +// response: handlerData.response, +// }, +// ); +// } +// } + +/** + * Creates transaction from navigation changes + */ +function historyCallback(_: { [key: string]: any }): void { + if (TransactionActivity.options.startTransactionOnLocationChange) { + TransactionActivity.startIdleTransaction(global.location.href, { + op: 'navigation', + sampled: true, + }); + } +} + +const historyHandler = { + callback: historyCallback, + type: 'history', +}; + +const xhrHandler = { + callback: xhrCallback, + type: 'xhr', +}; + +// tslint:disable-next-line: variable-name +export const TransactionActivityHandlers = [historyHandler, xhrHandler]; From 73c8cfe5b5d1447478ffbd8c532c5ecf28d898eb Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Tue, 19 Nov 2019 13:28:14 +0100 Subject: [PATCH 46/63] fix: Not initalized integration --- packages/integrations/src/transactionactivity.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/integrations/src/transactionactivity.ts b/packages/integrations/src/transactionactivity.ts index 6d9811c25309..184bb70015f9 100644 --- a/packages/integrations/src/transactionactivity.ts +++ b/packages/integrations/src/transactionactivity.ts @@ -79,11 +79,13 @@ export class TransactionActivity implements Integration { if (!TransactionActivity._isEnabled()) { return; } - // `${window.location.href}` will be used a temp transaction name - TransactionActivity.startIdleTransaction(`${window.location.href}`, { - op: 'pageload', - sampled: true, - }); + if (global.location && global.location.href) { + // `${global.location.href}` will be used a temp transaction name + TransactionActivity.startIdleTransaction(global.location.href, { + op: 'pageload', + sampled: true, + }); + } } /** @@ -93,6 +95,10 @@ export class TransactionActivity implements Integration { if (TransactionActivity._enabled !== undefined) { return TransactionActivity._enabled; } + // This happens only in test cases where the integration isn't initalized properly + if (!TransactionActivity.options || isNaN(TransactionActivity.options.tracesSampleRate)) { + return false; + } TransactionActivity._enabled = Math.random() > TransactionActivity.options.tracesSampleRate ? false : true; return TransactionActivity._enabled; } From b62ea41824584bf8d52006c363f83f4812d48190 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 20 Nov 2019 09:13:29 +0100 Subject: [PATCH 47/63] fix: Use scope instead of configureScope --- .../integrations/src/transactionactivity.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/integrations/src/transactionactivity.ts b/packages/integrations/src/transactionactivity.ts index 184bb70015f9..80db06eb25f4 100644 --- a/packages/integrations/src/transactionactivity.ts +++ b/packages/integrations/src/transactionactivity.ts @@ -96,7 +96,8 @@ export class TransactionActivity implements Integration { return TransactionActivity._enabled; } // This happens only in test cases where the integration isn't initalized properly - if (!TransactionActivity.options || isNaN(TransactionActivity.options.tracesSampleRate)) { + // tslint:disable-next-line: strict-type-predicates + if (!TransactionActivity.options || typeof TransactionActivity.options.tracesSampleRate !== 'number') { return false; } TransactionActivity._enabled = Math.random() > TransactionActivity.options.tracesSampleRate ? false : true; @@ -111,6 +112,7 @@ export class TransactionActivity implements Integration { // Tracing is not enabled return undefined; } + const activeTransaction = TransactionActivity._activeTransaction; if (activeTransaction) { @@ -140,9 +142,11 @@ export class TransactionActivity implements Integration { TransactionActivity._activeTransaction = span; - hub.configureScope((scope: Scope) => { - scope.setSpan(span); - }); + // We need to do this workaround here and not use configureScope + // Reason being at the time we start the inital transaction we do not have a client bound on the hub yet + // therefore configureScope wouldn't be executed and we would miss setting the transaction + // tslint:disable-next-line: no-unsafe-any + (hub as any).getScope().setSpan(span); // The reason we do this here is because of cached responses // If we start and transaction without an activity it would never finish since there is no activity @@ -185,6 +189,10 @@ export class TransactionActivity implements Integration { // Tracing is not enabled return 0; } + + // We want to clear the timeout also here since we push a new activity + clearTimeout(TransactionActivity._debounce); + const _getCurrentHub = TransactionActivity._getCurrentHub; if (spanContext && _getCurrentHub) { const hub = _getCurrentHub(); @@ -211,6 +219,7 @@ export class TransactionActivity implements Integration { // Tracing is not enabled return; } + const activity = TransactionActivity._activities[id]; if (activity) { if (activity.span) { From 3e28014ef2faf8fbe056bd91e48d87689d430ed0 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 20 Nov 2019 09:23:53 +0100 Subject: [PATCH 48/63] fix: Scope --- packages/integrations/src/transactionactivity.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/integrations/src/transactionactivity.ts b/packages/integrations/src/transactionactivity.ts index 80db06eb25f4..6fa86bdfc830 100644 --- a/packages/integrations/src/transactionactivity.ts +++ b/packages/integrations/src/transactionactivity.ts @@ -1,4 +1,4 @@ -import { EventProcessor, Hub, Integration, Scope, Span, SpanContext } from '@sentry/types'; +import { EventProcessor, Hub, Integration, Span, SpanContext } from '@sentry/types'; import { getGlobalObject } from '@sentry/utils'; /** JSDoc */ From 707e622cb99d38a053c8cb29ab2ba0b76ce87460 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 20 Nov 2019 09:56:52 +0100 Subject: [PATCH 49/63] feat: Add data before finish span --- packages/hub/src/span.ts | 20 +++-------- .../integrations/src/transactionactivity.ts | 14 +++++--- packages/types/src/span.ts | 35 +++++++++++++++++++ 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/packages/hub/src/span.ts b/packages/hub/src/span.ts index f15242e5ccb9..ce4c8e7bc73e 100644 --- a/packages/hub/src/span.ts +++ b/packages/hub/src/span.ts @@ -210,9 +210,7 @@ export class Span implements SpanInterface, SpanContext { } /** - * Sets the tag attribute on the current span - * @param key Tag key - * @param value Tag value + * @inheritDoc */ public setTag(key: string, value: string): this { this.tags = { ...this.tags, [key]: value }; @@ -220,9 +218,7 @@ export class Span implements SpanInterface, SpanContext { } /** - * Sets the data attribute on the current span - * @param key Data key - * @param value Data value + * @inheritDoc */ public setData(key: string, value: any): this { this.data = { ...this.data, [key]: value }; @@ -230,9 +226,7 @@ export class Span implements SpanInterface, SpanContext { } /** - * Sets the data attribute on the current span - * @param key Data key - * @param value Data value + * @inheritDoc */ public setFailure(): this { this.setTag('status', 'failure'); @@ -240,9 +234,7 @@ export class Span implements SpanInterface, SpanContext { } /** - * Sets the data attribute on the current span - * @param key Data key - * @param value Data value + * @inheritDoc */ public setSuccess(): this { this.setTag('status', 'success'); @@ -250,9 +242,7 @@ export class Span implements SpanInterface, SpanContext { } /** - * Sets the data attribute on the current span - * @param key Data key - * @param value Data value + * @inheritDoc */ public isSuccess(): boolean { return this.tags.status !== 'failure'; diff --git a/packages/integrations/src/transactionactivity.ts b/packages/integrations/src/transactionactivity.ts index 6fa86bdfc830..09f2d5e99230 100644 --- a/packages/integrations/src/transactionactivity.ts +++ b/packages/integrations/src/transactionactivity.ts @@ -214,7 +214,7 @@ export class TransactionActivity implements Integration { /** * Removes activity and finishes the span in case there is one */ - public static popActivity(id: number): void { + public static popActivity(id: number, spanData?: { [key: string]: any }): void { if (!TransactionActivity._isEnabled()) { // Tracing is not enabled return; @@ -222,8 +222,14 @@ export class TransactionActivity implements Integration { const activity = TransactionActivity._activities[id]; if (activity) { - if (activity.span) { - activity.span.finish(); + const span = activity.span; + if (span) { + if (spanData) { + Object.keys(spanData).forEach((key: string) => { + span.setData(key, spanData[key]); + }); + } + span.finish(); } // tslint:disable-next-line: no-dynamic-delete delete TransactionActivity._activities[id]; @@ -247,7 +253,7 @@ export class TransactionActivity implements Integration { function xhrCallback(handlerData: { [key: string]: any }): void { // tslint:disable: no-unsafe-any if (handlerData.requestComplete && handlerData.xhr.__sentry_xhr_activity_id__) { - TransactionActivity.popActivity(handlerData.xhr.__sentry_xhr_activity_id__); + TransactionActivity.popActivity(handlerData.xhr.__sentry_xhr_activity_id__, handlerData.xhr.__sentry_xhr__); return; } // We only capture complete, non-sentry requests diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index 851328ffb0a5..74f17fb6438f 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -8,6 +8,41 @@ export interface Span { getTraceContext(): object; /** Convert the object to JSON */ toJSON(): object; + + /** + * Sets the tag attribute on the current span + * @param key Tag key + * @param value Tag value + */ + setTag(key: string, value: string): this; + + /** + * Sets the data attribute on the current span + * @param key Data key + * @param value Data value + */ + setData(key: string, value: any): this; + + /** + * Sets the data attribute on the current span + * @param key Data key + * @param value Data value + */ + setFailure(): this; + + /** + * Sets the data attribute on the current span + * @param key Data key + * @param value Data value + */ + setSuccess(): this; + + /** + * Sets the data attribute on the current span + * @param key Data key + * @param value Data value + */ + isSuccess(): boolean; } /** Interface holder all properties that can be set on a Span on creation. */ From 75e71fe07ff22237d0dd7d56bfe243fc065f5756 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 20 Nov 2019 14:50:45 +0100 Subject: [PATCH 50/63] fix: Remove unused options --- packages/integrations/src/transactionactivity.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/integrations/src/transactionactivity.ts b/packages/integrations/src/transactionactivity.ts index 09f2d5e99230..7bd730ac2651 100644 --- a/packages/integrations/src/transactionactivity.ts +++ b/packages/integrations/src/transactionactivity.ts @@ -4,11 +4,6 @@ import { getGlobalObject } from '@sentry/utils'; /** JSDoc */ interface TransactionActivityOptions { idleTimeout: number; - patchHistory: boolean; - /** - * Called when an history change happend - */ - onLocationChange(state: any): string; startTransactionOnLocationChange: boolean; tracesSampleRate: number; } @@ -60,8 +55,6 @@ export class TransactionActivity implements Integration { public constructor(public readonly _options?: Partial) { const defaults = { idleTimeout: 500, - onLocationChange: () => global.location.href, - patchHistory: true, startTransactionOnLocationChange: true, tracesSampleRate: 1, }; From fa506ce1e289e2217b9d3ee68a48e7e94f2db48f Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 20 Nov 2019 16:50:43 +0100 Subject: [PATCH 51/63] feat: Move Hub and Span to apm package --- dangerfile.ts | 2 +- package.json | 1 + packages/apm/.npmignore | 4 + packages/apm/README.md | 27 ++++++ packages/apm/package.json | 75 +++++++++++++++++ packages/apm/src/hub.ts | 84 +++++++++++++++++++ packages/apm/src/index.ts | 5 ++ .../src => apm/src/integrations}/express.ts | 6 +- packages/apm/src/integrations/index.ts | 3 + .../src => apm/src/integrations}/tracing.ts | 6 +- .../src/integrations}/transactionactivity.ts | 6 +- packages/{hub => apm}/src/span.ts | 5 +- packages/{hub => apm}/test/span.test.ts | 4 +- .../test/transactionactivity.test.ts | 2 +- packages/apm/tsconfig.build.json | 8 ++ packages/apm/tsconfig.esm.json | 8 ++ packages/apm/tsconfig.json | 9 ++ packages/apm/tslint.json | 3 + packages/browser/src/index.ts | 2 - packages/core/src/index.ts | 3 +- packages/hub/src/hub.ts | 60 ------------- packages/hub/src/index.ts | 1 - packages/hub/src/scope.ts | 13 ++- packages/hub/tsconfig.json | 2 +- packages/integrations/package.json | 1 - packages/integrations/src/index.ts | 3 - packages/minimal/src/index.ts | 12 +-- packages/node/src/index.ts | 2 - packages/types/src/hub.ts | 13 --- yarn.lock | 31 +++++++ 30 files changed, 293 insertions(+), 108 deletions(-) create mode 100644 packages/apm/.npmignore create mode 100644 packages/apm/README.md create mode 100644 packages/apm/package.json create mode 100644 packages/apm/src/hub.ts create mode 100644 packages/apm/src/index.ts rename packages/{integrations/src => apm/src/integrations}/express.ts (97%) create mode 100644 packages/apm/src/integrations/index.ts rename packages/{integrations/src => apm/src/integrations}/tracing.ts (97%) rename packages/{integrations/src => apm/src/integrations}/transactionactivity.ts (98%) rename packages/{hub => apm}/src/span.ts (98%) rename packages/{hub => apm}/test/span.test.ts (98%) rename packages/{integrations => apm}/test/transactionactivity.test.ts (96%) create mode 100644 packages/apm/tsconfig.build.json create mode 100644 packages/apm/tsconfig.esm.json create mode 100644 packages/apm/tsconfig.json create mode 100644 packages/apm/tslint.json diff --git a/dangerfile.ts b/dangerfile.ts index fa1fe26e3ed8..5654eb280dfe 100644 --- a/dangerfile.ts +++ b/dangerfile.ts @@ -5,7 +5,7 @@ import { resolve } from 'path'; import tslint from 'danger-plugin-tslint'; import { prettyResults } from 'danger-plugin-tslint/dist/prettyResults'; -const packages = ['browser', 'core', 'hub', 'integrations', 'minimal', 'node', 'types', 'utils']; +const packages = ['apm', 'browser', 'core', 'hub', 'integrations', 'minimal', 'node', 'types', 'utils']; export default async () => { if (!danger.github) { diff --git a/package.json b/package.json index f4ffdb970e47..9e55fc3b0eab 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "yarn": "1.13.0" }, "workspaces": [ + "packages/apm", "packages/browser", "packages/core", "packages/hub", diff --git a/packages/apm/.npmignore b/packages/apm/.npmignore new file mode 100644 index 000000000000..14e80551ae7c --- /dev/null +++ b/packages/apm/.npmignore @@ -0,0 +1,4 @@ +* +!/dist/**/* +!/esm/**/* +*.tsbuildinfo diff --git a/packages/apm/README.md b/packages/apm/README.md new file mode 100644 index 000000000000..4d54c4d983f5 --- /dev/null +++ b/packages/apm/README.md @@ -0,0 +1,27 @@ +

+ + + +
+

+ +# Sentry APM Extensions + +# TODO + +[![npm version](https://img.shields.io/npm/v/@sentry/core.svg)](https://www.npmjs.com/package/@sentry/core) +[![npm dm](https://img.shields.io/npm/dm/@sentry/core.svg)](https://www.npmjs.com/package/@sentry/core) +[![npm dt](https://img.shields.io/npm/dt/@sentry/core.svg)](https://www.npmjs.com/package/@sentry/core) +[![typedoc](https://img.shields.io/badge/docs-typedoc-blue.svg)](http://getsentry.github.io/sentry-javascript/) + +## Links + +- [Official SDK Docs](https://docs.sentry.io/quickstart/) +- [TypeDoc](http://getsentry.github.io/sentry-javascript/) + +## General + +This package contains interface definitions, base classes and utilities for building Sentry JavaScript SDKs, like +`@sentry/node` or `@sentry/browser`. + +Please consider all classes and exported functions and interfaces `internal`. diff --git a/packages/apm/package.json b/packages/apm/package.json new file mode 100644 index 000000000000..f8423cafb6e8 --- /dev/null +++ b/packages/apm/package.json @@ -0,0 +1,75 @@ +{ + "name": "@sentry/apm", + "version": "5.10.0-beta.3", + "description": "Extensions for APM", + "repository": "git://github.com/getsentry/sentry-javascript.git", + "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/core", + "author": "Sentry", + "license": "BSD-3-Clause", + "engines": { + "node": ">=6" + }, + "main": "dist/index.js", + "module": "esm/index.js", + "types": "dist/index.d.ts", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@sentry/hub": "5.10.0-beta.3", + "@sentry/minimal": "5.10.0-beta.3", + "@sentry/types": "5.10.0-beta.3", + "@sentry/utils": "5.10.0-beta.3", + "tslib": "^1.9.3" + }, + "devDependencies": { + "@types/express": "^4.17.1", + "jest": "^24.7.1", + "npm-run-all": "^4.1.2", + "prettier": "^1.17.0", + "prettier-check": "^2.0.0", + "rimraf": "^2.6.3", + "tslint": "^5.16.0", + "typescript": "^3.4.5" + }, + "scripts": { + "build": "run-p build:es5 build:esm", + "build:es5": "tsc -p tsconfig.build.json", + "build:esm": "tsc -p tsconfig.esm.json", + "build:watch": "run-p build:watch:es5 build:watch:esm", + "build:watch:es5": "tsc -p tsconfig.build.json -w --preserveWatchOutput", + "build:watch:esm": "tsc -p tsconfig.esm.json -w --preserveWatchOutput", + "clean": "rimraf dist coverage", + "link:yarn": "yarn link", + "lint": "run-s lint:prettier lint:tslint", + "lint:prettier": "prettier-check \"{src,test}/**/*.ts\"", + "lint:tslint": "tslint -t stylish -p .", + "lint:tslint:json": "tslint --format json -p . | tee lint-results.json", + "fix": "run-s fix:tslint fix:prettier", + "fix:prettier": "prettier --write \"{src,test}/**/*.ts\"", + "fix:tslint": "tslint --fix -t stylish -p .", + "test": "jest", + "test:watch": "jest --watch" + }, + "jest": { + "collectCoverage": true, + "transform": { + "^.+\\.ts$": "ts-jest" + }, + "moduleFileExtensions": [ + "js", + "ts" + ], + "testEnvironment": "node", + "testMatch": [ + "**/*.test.ts" + ], + "globals": { + "ts-jest": { + "tsConfig": "./tsconfig.json", + "diagnostics": false + } + } + }, + "sideEffects": false +} diff --git a/packages/apm/src/hub.ts b/packages/apm/src/hub.ts new file mode 100644 index 000000000000..5084be50bf3b --- /dev/null +++ b/packages/apm/src/hub.ts @@ -0,0 +1,84 @@ +import { Hub as BaseHub } from '@sentry/hub'; +import { Hub as BaseHubInterface, SpanContext } from '@sentry/types'; + +import { Span } from './span'; + +/** + * Checks whether given value is instance of Span + * @param span value to check + */ +function isSpanInstance(span: unknown): span is Span { + return span instanceof Span; +} + +/** + * Hub with APM extension methods + */ +export interface ApmHubInterface extends BaseHubInterface { + /** Returns all trace headers that are currently on the top scope. */ + traceHeaders(): { [key: string]: string }; + + /** + * This functions starts a span. If argument passed is of type `Span`, it'll run sampling on it if configured + * and attach a `SpanRecorder`. If it's of type `SpanContext` and there is already a `Span` on the Scope, + * the created Span will have a reference to it and become it's child. Otherwise it'll crete a new `Span`. + * + * @param span Already constructed span which should be started or properties with which the span should be created + */ + startSpan(span?: Span | SpanContext, forceNoChild?: boolean): Span; +} + +/** + * APM Hub + */ +export class Hub extends BaseHub implements ApmHubInterface { + /** + * @inheritDoc + */ + public traceHeaders(): { [key: string]: string } { + const scope = this.getScope(); + if (scope) { + const span = scope.getSpan(); + if (span) { + return { + 'sentry-trace': span.toTraceparent(), + }; + } + } + return {}; + } + + /** + * @inheritDoc + */ + public startSpan(spanOrSpanContext?: Span | SpanContext, forceNoChild: boolean = false): Span { + const scope = this.getScope(); + const client = this.getClient(); + let span; + + if (!isSpanInstance(spanOrSpanContext) && !forceNoChild) { + if (scope) { + const parentSpan = scope.getSpan() as Span; + if (parentSpan) { + span = parentSpan.child(spanOrSpanContext); + } + } + } + + if (!isSpanInstance(span)) { + span = new Span(spanOrSpanContext, this); + } + + if (span.sampled === undefined && span.transaction !== undefined) { + const sampleRate = (client && client.getOptions().tracesSampleRate) || 0; + span.sampled = Math.random() < sampleRate; + } + + if (span.sampled) { + const experimentsOptions = (client && client.getOptions()._experiments) || {}; + span.initFinishedSpans(experimentsOptions.maxSpans); + } + + return span; + } +} diff --git a/packages/apm/src/index.ts b/packages/apm/src/index.ts new file mode 100644 index 000000000000..26bbaa9c7627 --- /dev/null +++ b/packages/apm/src/index.ts @@ -0,0 +1,5 @@ +import * as ApmIntegrations from './integrations'; + +export { Hub } from './hub'; +export { ApmIntegrations as Integrations }; +export { Span, TRACEPARENT_REGEXP } from './span'; diff --git a/packages/integrations/src/express.ts b/packages/apm/src/integrations/express.ts similarity index 97% rename from packages/integrations/src/express.ts rename to packages/apm/src/integrations/express.ts index 6916f849c360..f58e5286e678 100644 --- a/packages/integrations/src/express.ts +++ b/packages/apm/src/integrations/express.ts @@ -1,8 +1,10 @@ -import { EventProcessor, Hub, Integration } from '@sentry/types'; +import { EventProcessor, Integration } from '@sentry/types'; import { logger } from '@sentry/utils'; // tslint:disable-next-line:no-implicit-dependencies import { Application, ErrorRequestHandler, NextFunction, Request, RequestHandler, Response } from 'express'; +import { Hub } from '../hub'; + /** * Express integration * @@ -37,7 +39,7 @@ export class Express implements Integration { */ public setupOnce(_addGlobalEventProcessor: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void { if (!this._app) { - logger.error('ExpressIntegration is missing an Express instancex'); + logger.error('ExpressIntegration is missing an Express instance'); return; } instrumentMiddlewares(this._app, getCurrentHub); diff --git a/packages/apm/src/integrations/index.ts b/packages/apm/src/integrations/index.ts new file mode 100644 index 000000000000..035440a364b0 --- /dev/null +++ b/packages/apm/src/integrations/index.ts @@ -0,0 +1,3 @@ +export { Express } from './express'; +export { Tracing } from './tracing'; +export { TransactionActivity, TransactionActivityHandlers } from './transactionactivity'; diff --git a/packages/integrations/src/tracing.ts b/packages/apm/src/integrations/tracing.ts similarity index 97% rename from packages/integrations/src/tracing.ts rename to packages/apm/src/integrations/tracing.ts index 2619c209371f..0c0c85b89c4d 100644 --- a/packages/integrations/src/tracing.ts +++ b/packages/apm/src/integrations/tracing.ts @@ -1,6 +1,9 @@ -import { EventProcessor, Hub, Integration } from '@sentry/types'; +import { makeMain } from '@sentry/hub'; +import { EventProcessor, Integration } from '@sentry/types'; import { fill, getGlobalObject, isMatchingPattern, logger, supportsNativeFetch } from '@sentry/utils'; +import { Hub } from '../hub'; + /** JSDoc */ interface TracingOptions { tracingOrigins?: Array; @@ -35,6 +38,7 @@ export class Tracing implements Integration { * @param _options TracingOptions */ public constructor(private readonly _options: TracingOptions = {}) { + makeMain(new Hub()); if (!Array.isArray(_options.tracingOrigins) || _options.tracingOrigins.length === 0) { const defaultTracingOrigins = ['localhost', /^\//]; logger.warn( diff --git a/packages/integrations/src/transactionactivity.ts b/packages/apm/src/integrations/transactionactivity.ts similarity index 98% rename from packages/integrations/src/transactionactivity.ts rename to packages/apm/src/integrations/transactionactivity.ts index 7bd730ac2651..2164fdb99f7b 100644 --- a/packages/integrations/src/transactionactivity.ts +++ b/packages/apm/src/integrations/transactionactivity.ts @@ -1,6 +1,9 @@ -import { EventProcessor, Hub, Integration, Span, SpanContext } from '@sentry/types'; +import { makeMain } from '@sentry/hub'; +import { EventProcessor, Integration, Span, SpanContext } from '@sentry/types'; import { getGlobalObject } from '@sentry/utils'; +import { Hub } from '../hub'; + /** JSDoc */ interface TransactionActivityOptions { idleTimeout: number; @@ -53,6 +56,7 @@ export class TransactionActivity implements Integration { * @inheritDoc */ public constructor(public readonly _options?: Partial) { + makeMain(new Hub()); const defaults = { idleTimeout: 500, startTransactionOnLocationChange: true, diff --git a/packages/hub/src/span.ts b/packages/apm/src/span.ts similarity index 98% rename from packages/hub/src/span.ts rename to packages/apm/src/span.ts index ce4c8e7bc73e..473a2f8750b1 100644 --- a/packages/hub/src/span.ts +++ b/packages/apm/src/span.ts @@ -1,9 +1,10 @@ // tslint:disable:max-classes-per-file +import { getCurrentHub } from '@sentry/hub'; import { Span as SpanInterface, SpanContext } from '@sentry/types'; import { logger, timestampWithMs, uuid4 } from '@sentry/utils'; -import { getCurrentHub, Hub } from './hub'; +import { Hub } from './hub'; export const TRACEPARENT_REGEXP = new RegExp( '^[ \\t]*' + // whitespace @@ -54,7 +55,7 @@ export class Span implements SpanInterface, SpanContext { /** * The reference to the current hub. */ - private readonly _hub: Hub = getCurrentHub(); + private readonly _hub: Hub = (getCurrentHub() as unknown) as Hub; /** * @inheritDoc diff --git a/packages/hub/test/span.test.ts b/packages/apm/test/span.test.ts similarity index 98% rename from packages/hub/test/span.test.ts rename to packages/apm/test/span.test.ts index 7cd61e01d2e5..2edced5a2711 100644 --- a/packages/hub/test/span.test.ts +++ b/packages/apm/test/span.test.ts @@ -1,4 +1,6 @@ -import { Hub, Scope, Span, TRACEPARENT_REGEXP } from '../src'; +import { Scope } from '@sentry/hub'; + +import { Hub, Span, TRACEPARENT_REGEXP } from '../src'; describe('Span', () => { let hub: Hub; diff --git a/packages/integrations/test/transactionactivity.test.ts b/packages/apm/test/transactionactivity.test.ts similarity index 96% rename from packages/integrations/test/transactionactivity.test.ts rename to packages/apm/test/transactionactivity.test.ts index 6b87785b45b6..a480a8347714 100644 --- a/packages/integrations/test/transactionactivity.test.ts +++ b/packages/apm/test/transactionactivity.test.ts @@ -1,4 +1,4 @@ -import { TransactionActivity } from '../src/transactionactivity'; +import { TransactionActivity } from '../src/integrations/transactionactivity'; const transactionActivity: TransactionActivity = new TransactionActivity(); diff --git a/packages/apm/tsconfig.build.json b/packages/apm/tsconfig.build.json new file mode 100644 index 000000000000..a263a085c70a --- /dev/null +++ b/packages/apm/tsconfig.build.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "outDir": "dist" + }, + "include": ["src/**/*"] +} diff --git a/packages/apm/tsconfig.esm.json b/packages/apm/tsconfig.esm.json new file mode 100644 index 000000000000..33a3842217d4 --- /dev/null +++ b/packages/apm/tsconfig.esm.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.esm.json", + "compilerOptions": { + "baseUrl": ".", + "outDir": "esm" + }, + "include": ["src/**/*"] +} diff --git a/packages/apm/tsconfig.json b/packages/apm/tsconfig.json new file mode 100644 index 000000000000..55b38e135ae2 --- /dev/null +++ b/packages/apm/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.build.json", + "include": ["src/**/*.ts", "test/**/*.ts"], + "exclude": ["dist"], + "compilerOptions": { + "rootDir": ".", + "types": ["node", "jest"] + } +} diff --git a/packages/apm/tslint.json b/packages/apm/tslint.json new file mode 100644 index 000000000000..3016a27a85cc --- /dev/null +++ b/packages/apm/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "@sentry/typescript/tslint" +} diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index 4be86ae0067c..af6df17741a7 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -30,8 +30,6 @@ export { setTag, setTags, setUser, - startSpan, - Span, withScope, } from '@sentry/core'; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 3a3508aa3b15..ad7e542cbd66 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -10,10 +10,9 @@ export { setTag, setTags, setUser, - startSpan, withScope, } from '@sentry/minimal'; -export { addGlobalEventProcessor, getCurrentHub, getHubFromCarrier, Hub, Scope, Span } from '@sentry/hub'; +export { addGlobalEventProcessor, getCurrentHub, getHubFromCarrier, Hub, Scope } from '@sentry/hub'; export { API } from './api'; export { BaseClient } from './baseclient'; export { BackendClass, BaseBackend } from './basebackend'; diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index 7928ce73f359..27ff474fc18e 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -8,7 +8,6 @@ import { Integration, IntegrationClass, Severity, - SpanContext, User, } from '@sentry/types'; import { @@ -23,7 +22,6 @@ import { import { Carrier, Layer } from './interfaces'; import { Scope } from './scope'; -import { Span } from './span'; declare module 'domain' { export let active: Domain; @@ -35,14 +33,6 @@ declare module 'domain' { } } -/** - * Checks whether given value is instance of Span - * @param span value to check - */ -function isSpanInstance(span: unknown): span is Span { - return span instanceof Span; -} - /** * API compatibility version of this hub. * @@ -385,56 +375,6 @@ export class Hub implements HubInterface { return null; } } - - /** - * @inheritDoc - */ - public traceHeaders(): { [key: string]: string } { - const scope = this.getScope(); - if (scope) { - const span = scope.getSpan(); - if (span) { - return { - 'sentry-trace': span.toTraceparent(), - }; - } - } - return {}; - } - - /** - * @inheritDoc - */ - public startSpan(spanOrSpanContext?: Span | SpanContext, forceNoChild: boolean = false): Span { - const scope = this.getScope(); - const client = this.getClient(); - let span; - - if (!isSpanInstance(spanOrSpanContext) && !forceNoChild) { - if (scope) { - const parentSpan = scope.getSpan(); - if (parentSpan) { - span = parentSpan.child(spanOrSpanContext); - } - } - } - - if (!isSpanInstance(span)) { - span = new Span(spanOrSpanContext, this); - } - - if (span.sampled === undefined && span.transaction !== undefined) { - const sampleRate = (client && client.getOptions().tracesSampleRate) || 0; - span.sampled = Math.random() < sampleRate; - } - - if (span.sampled) { - const experimentsOptions = (client && client.getOptions()._experiments) || {}; - span.initFinishedSpans(experimentsOptions.maxSpans); - } - - return span; - } } /** Returns the global shim registry. */ diff --git a/packages/hub/src/index.ts b/packages/hub/src/index.ts index a380a431945e..6656b1b24df9 100644 --- a/packages/hub/src/index.ts +++ b/packages/hub/src/index.ts @@ -1,4 +1,3 @@ export { Carrier, Layer } from './interfaces'; export { addGlobalEventProcessor, Scope } from './scope'; export { getCurrentHub, getHubFromCarrier, getMainCarrier, Hub, makeMain, setHubOnCarrier } from './hub'; -export { Span, TRACEPARENT_REGEXP } from './span'; diff --git a/packages/hub/src/scope.ts b/packages/hub/src/scope.ts index 54ffde8bb73b..97a3c24500c3 100644 --- a/packages/hub/src/scope.ts +++ b/packages/hub/src/scope.ts @@ -1,8 +1,15 @@ -import { Breadcrumb, Event, EventHint, EventProcessor, Scope as ScopeInterface, Severity, User } from '@sentry/types'; +import { + Breadcrumb, + Event, + EventHint, + EventProcessor, + Scope as ScopeInterface, + Severity, + Span, + User, +} from '@sentry/types'; import { getGlobalObject, isThenable, normalize, SyncPromise, timestampWithMs } from '@sentry/utils'; -import { Span } from './span'; - /** * Holds additional event information. {@link Scope.applyToEvent} will be * called by the client before an event will be sent. diff --git a/packages/hub/tsconfig.json b/packages/hub/tsconfig.json index 55b38e135ae2..c5b01e1bb513 100644 --- a/packages/hub/tsconfig.json +++ b/packages/hub/tsconfig.json @@ -1,6 +1,6 @@ { "extends": "./tsconfig.build.json", - "include": ["src/**/*.ts", "test/**/*.ts"], + "include": ["src/**/*.ts", "test/**/*.ts", "../apm/test/span.test.ts"], "exclude": ["dist"], "compilerOptions": { "rootDir": ".", diff --git a/packages/integrations/package.json b/packages/integrations/package.json index 25048c5744a2..77e616e5c2b7 100644 --- a/packages/integrations/package.json +++ b/packages/integrations/package.json @@ -21,7 +21,6 @@ "tslib": "^1.9.3" }, "devDependencies": { - "@types/express": "^4.17.1", "chai": "^4.1.2", "jest": "^24.7.1", "npm-run-all": "^4.1.2", diff --git a/packages/integrations/src/index.ts b/packages/integrations/src/index.ts index c21825f0e60d..c1e8d69794ad 100644 --- a/packages/integrations/src/index.ts +++ b/packages/integrations/src/index.ts @@ -3,12 +3,9 @@ export { CaptureConsole } from './captureconsole'; export { Debug } from './debug'; export { Dedupe } from './dedupe'; export { Ember } from './ember'; -export { Express } from './express'; export { ExtraErrorData } from './extraerrordata'; export { ReportingObserver } from './reportingobserver'; export { RewriteFrames } from './rewriteframes'; export { SessionTiming } from './sessiontiming'; -export { Tracing } from './tracing'; export { Transaction } from './transaction'; -export { TransactionActivity, TransactionActivityHandlers } from './transactionactivity'; export { Vue } from './vue'; diff --git a/packages/minimal/src/index.ts b/packages/minimal/src/index.ts index ebc465dbe97c..6df2d04fc698 100644 --- a/packages/minimal/src/index.ts +++ b/packages/minimal/src/index.ts @@ -1,5 +1,5 @@ import { getCurrentHub, Hub, Scope } from '@sentry/hub'; -import { Breadcrumb, Event, Severity, Span, SpanContext, User } from '@sentry/types'; +import { Breadcrumb, Event, Severity, User } from '@sentry/types'; /** * This calls a function on the current hub. @@ -167,13 +167,3 @@ export function withScope(callback: (scope: Scope) => void): void { export function _callOnClient(method: string, ...args: any[]): void { callOnHub('_invokeClient', method, ...args); } - -/** - * This functions starts a span. If just a `SpanContext` is passed and there is already a Span - * on the Scope, the created Span will have a reference to the one on the Scope. - * - * @param spanContext Properties with which the span should be created - */ -export function startSpan(spanContext?: SpanContext): Span { - return callOnHub('startSpan', spanContext); -} diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index e12402a23daf..d3621d525304 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -30,8 +30,6 @@ export { setTag, setTags, setUser, - startSpan, - Span, withScope, } from '@sentry/core'; diff --git a/packages/types/src/hub.ts b/packages/types/src/hub.ts index ccc8fa410e9a..a22d9df988b3 100644 --- a/packages/types/src/hub.ts +++ b/packages/types/src/hub.ts @@ -4,7 +4,6 @@ import { Event, EventHint } from './event'; import { Integration, IntegrationClass } from './integration'; import { Scope } from './scope'; import { Severity } from './severity'; -import { Span, SpanContext } from './span'; import { User } from './user'; /** @@ -168,16 +167,4 @@ export interface Hub { /** Returns the integration if installed on the current client. */ getIntegration(integration: IntegrationClass): T | null; - - /** Returns all trace headers that are currently on the top scope. */ - traceHeaders(): { [key: string]: string }; - - /** - * This functions starts a span. If argument passed is of type `Span`, it'll run sampling on it if configured - * and attach a `SpanRecorder`. If it's of type `SpanContext` and there is already a `Span` on the Scope, - * the created Span will have a reference to it and become it's child. Otherwise it'll crete a new `Span`. - * - * @param span Already constructed span which should be started or properties with which the span should be created - */ - startSpan(span?: Span | SpanContext, forceNoChild?: boolean): Span; } diff --git a/yarn.lock b/yarn.lock index 3eac15621d74..fa4fcba269f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1092,6 +1092,37 @@ universal-user-agent "^2.0.0" url-template "^2.0.8" +"@sentry/hub@5.10.0-beta.3": + version "5.10.0-beta.3" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.10.0-beta.3.tgz#12ac48561411ca8be6be3191b8b43e73a7eda68c" + integrity sha512-zCw/lOaNskP4bDUBSMK5h5Mvb9cYAZI0LmlCGNHLpd+82R5+VUCzZBMlcAnaQHfXoTc2hPITK+A29YeC8PvJxQ== + dependencies: + "@sentry/types" "5.10.0-beta.3" + "@sentry/utils" "5.10.0-beta.3" + tslib "^1.9.3" + +"@sentry/minimal@5.10.0-beta.3": + version "5.10.0-beta.3" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.10.0-beta.3.tgz#51d0ecff4863a04082f2b4d907016edfa5a85d69" + integrity sha512-V+Ln8QHkGJeEWEVXqjD8wrfR5vBcdlOcUmDXOq60UDbBF8i6PsPoKsO8xHnIY8wQUmN4/aV301tc0r2uaswX5g== + dependencies: + "@sentry/hub" "5.10.0-beta.3" + "@sentry/types" "5.10.0-beta.3" + tslib "^1.9.3" + +"@sentry/types@5.10.0-beta.3": + version "5.10.0-beta.3" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.10.0-beta.3.tgz#f34b81e5b1286147e5ba173baea23897f2def6e3" + integrity sha512-4CmlpvuUkhPc4JLrxp4z8W/N4XP6xTbsDx9rNYbUebWDgbHfz+vbbTJihMWzpZU7V4/YM+P8ik2Dgaflb5uAdw== + +"@sentry/utils@5.10.0-beta.3": + version "5.10.0-beta.3" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.10.0-beta.3.tgz#a327e4e5d90b547b918e2ed743ae51ef1a11fadf" + integrity sha512-frcC6C94LTXa8M8aiAjJ9mebhY1N90/VY+ouHwYcivUQRlz3zKdfEOPO9+uEeZP3hhddvljk3Ke0K9z8JgDTFQ== + dependencies: + "@sentry/types" "5.10.0-beta.3" + tslib "^1.9.3" + "@sinonjs/commons@^1", "@sinonjs/commons@^1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.4.0.tgz#7b3ec2d96af481d7a0321252e7b1c94724ec5a78" From d8c75747da7fbc15f83e149d5d85a12cf6b1a9e2 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 20 Nov 2019 17:56:41 +0100 Subject: [PATCH 52/63] fix: Node build --- packages/apm/package.json | 10 +++--- packages/apm/src/integrations/tracing.ts | 1 + .../src/integrations/transactionactivity.ts | 1 + packages/node/package.json | 1 + packages/node/src/handlers.ts | 36 ++++++++++--------- packages/node/src/integrations/http.ts | 24 ++++++++----- yarn.lock | 31 ---------------- 7 files changed, 44 insertions(+), 60 deletions(-) diff --git a/packages/apm/package.json b/packages/apm/package.json index f8423cafb6e8..37fdbfa914f3 100644 --- a/packages/apm/package.json +++ b/packages/apm/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/apm", - "version": "5.10.0-beta.3", + "version": "5.9.0", "description": "Extensions for APM", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/core", @@ -16,10 +16,10 @@ "access": "public" }, "dependencies": { - "@sentry/hub": "5.10.0-beta.3", - "@sentry/minimal": "5.10.0-beta.3", - "@sentry/types": "5.10.0-beta.3", - "@sentry/utils": "5.10.0-beta.3", + "@sentry/hub": "5.8.0", + "@sentry/minimal": "5.8.0", + "@sentry/types": "5.7.1", + "@sentry/utils": "5.8.0", "tslib": "^1.9.3" }, "devDependencies": { diff --git a/packages/apm/src/integrations/tracing.ts b/packages/apm/src/integrations/tracing.ts index 0c0c85b89c4d..6a72c8b81323 100644 --- a/packages/apm/src/integrations/tracing.ts +++ b/packages/apm/src/integrations/tracing.ts @@ -38,6 +38,7 @@ export class Tracing implements Integration { * @param _options TracingOptions */ public constructor(private readonly _options: TracingOptions = {}) { + // TODO makeMain(new Hub()); if (!Array.isArray(_options.tracingOrigins) || _options.tracingOrigins.length === 0) { const defaultTracingOrigins = ['localhost', /^\//]; diff --git a/packages/apm/src/integrations/transactionactivity.ts b/packages/apm/src/integrations/transactionactivity.ts index 2164fdb99f7b..a26ac1bc5dad 100644 --- a/packages/apm/src/integrations/transactionactivity.ts +++ b/packages/apm/src/integrations/transactionactivity.ts @@ -56,6 +56,7 @@ export class TransactionActivity implements Integration { * @inheritDoc */ public constructor(public readonly _options?: Partial) { + // TODO makeMain(new Hub()); const defaults = { idleTimeout: 500, diff --git a/packages/node/package.json b/packages/node/package.json index b9f2be943ebf..2c4601254b03 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -16,6 +16,7 @@ "access": "public" }, "dependencies": { + "@sentry/apm": "5.9.0", "@sentry/core": "5.8.0", "@sentry/hub": "5.8.0", "@sentry/types": "5.7.1", diff --git a/packages/node/src/handlers.ts b/packages/node/src/handlers.ts index 05cb860e3480..bbdd834668c1 100644 --- a/packages/node/src/handlers.ts +++ b/packages/node/src/handlers.ts @@ -1,4 +1,5 @@ -import { captureException, getCurrentHub, Span, withScope } from '@sentry/core'; +import { Hub, Span } from '@sentry/apm'; +import { captureException, getCurrentHub, withScope } from '@sentry/core'; import { Event } from '@sentry/types'; import { forget, isString, logger, normalize } from '@sentry/utils'; import * as cookie from 'cookie'; @@ -30,21 +31,24 @@ export function tracingHandler(): ( // but `req.path` or `req.url` should do the job as well. We could unify this here. const reqMethod = (req.method || '').toUpperCase(); const reqUrl = req.url; - const hub = getCurrentHub(); - const transaction = hub.startSpan({ - transaction: `${reqMethod}|${reqUrl}`, - }); - hub.configureScope(scope => { - scope.setSpan(transaction); - }); - res.once('finish', () => { - if (res.statusCode >= 500) { - transaction.setFailure(); - } else { - transaction.setSuccess(); - } - transaction.finish(); - }); + // TODO + const hub = (getCurrentHub() as unknown) as Hub; + if (hub.startSpan) { + const transaction = hub.startSpan({ + transaction: `${reqMethod}|${reqUrl}`, + }); + hub.configureScope(scope => { + scope.setSpan(transaction); + }); + res.once('finish', () => { + if (res.statusCode >= 500) { + transaction.setFailure(); + } else { + transaction.setSuccess(); + } + transaction.finish(); + }); + } next(); }; } diff --git a/packages/node/src/integrations/http.ts b/packages/node/src/integrations/http.ts index f22a2b91c14d..3d0068526333 100644 --- a/packages/node/src/integrations/http.ts +++ b/packages/node/src/integrations/http.ts @@ -1,5 +1,7 @@ -import { getCurrentHub, Span } from '@sentry/core'; -import { Integration } from '@sentry/types'; +import { Hub } from '@sentry/apm'; +import { getCurrentHub } from '@sentry/core'; +import { makeMain } from '@sentry/hub'; +import { Integration, Span } from '@sentry/types'; import { fill, parseSemver } from '@sentry/utils'; import * as http from 'http'; import * as https from 'https'; @@ -31,6 +33,8 @@ export class Http implements Integration { * @inheritDoc */ public constructor(options: { breadcrumbs?: boolean; tracing?: boolean } = {}) { + // TODO + makeMain(new Hub()); this._breadcrumbs = typeof options.breadcrumbs === 'undefined' ? true : options.breadcrumbs; this._tracing = typeof options.tracing === 'undefined' ? false : options.tracing; } @@ -80,10 +84,14 @@ function createHandlerWrapper( let span: Span; if (tracingEnabled) { - span = getCurrentHub().startSpan({ - description: `${typeof options === 'string' || !options.method ? 'GET' : options.method}|${requestUrl}`, - op: 'request', - }); + // TODO + const hub = (getCurrentHub() as unknown) as Hub; + if (hub.startSpan) { + span = hub.startSpan({ + description: `${typeof options === 'string' || !options.method ? 'GET' : options.method}|${requestUrl}`, + op: 'request', + }); + } } return originalHandler @@ -93,7 +101,7 @@ function createHandlerWrapper( addRequestBreadcrumb('response', requestUrl, this, res); } // TODO: Mark >= 500 as failed as well? - if (tracingEnabled) { + if (tracingEnabled && span) { span.setSuccess(); span.finish(); } @@ -102,7 +110,7 @@ function createHandlerWrapper( if (breadcrumbsEnabled) { addRequestBreadcrumb('error', requestUrl, this); } - if (tracingEnabled) { + if (tracingEnabled && span) { span.setFailure(); span.finish(); } diff --git a/yarn.lock b/yarn.lock index fa4fcba269f2..3eac15621d74 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1092,37 +1092,6 @@ universal-user-agent "^2.0.0" url-template "^2.0.8" -"@sentry/hub@5.10.0-beta.3": - version "5.10.0-beta.3" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.10.0-beta.3.tgz#12ac48561411ca8be6be3191b8b43e73a7eda68c" - integrity sha512-zCw/lOaNskP4bDUBSMK5h5Mvb9cYAZI0LmlCGNHLpd+82R5+VUCzZBMlcAnaQHfXoTc2hPITK+A29YeC8PvJxQ== - dependencies: - "@sentry/types" "5.10.0-beta.3" - "@sentry/utils" "5.10.0-beta.3" - tslib "^1.9.3" - -"@sentry/minimal@5.10.0-beta.3": - version "5.10.0-beta.3" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.10.0-beta.3.tgz#51d0ecff4863a04082f2b4d907016edfa5a85d69" - integrity sha512-V+Ln8QHkGJeEWEVXqjD8wrfR5vBcdlOcUmDXOq60UDbBF8i6PsPoKsO8xHnIY8wQUmN4/aV301tc0r2uaswX5g== - dependencies: - "@sentry/hub" "5.10.0-beta.3" - "@sentry/types" "5.10.0-beta.3" - tslib "^1.9.3" - -"@sentry/types@5.10.0-beta.3": - version "5.10.0-beta.3" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.10.0-beta.3.tgz#f34b81e5b1286147e5ba173baea23897f2def6e3" - integrity sha512-4CmlpvuUkhPc4JLrxp4z8W/N4XP6xTbsDx9rNYbUebWDgbHfz+vbbTJihMWzpZU7V4/YM+P8ik2Dgaflb5uAdw== - -"@sentry/utils@5.10.0-beta.3": - version "5.10.0-beta.3" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.10.0-beta.3.tgz#a327e4e5d90b547b918e2ed743ae51ef1a11fadf" - integrity sha512-frcC6C94LTXa8M8aiAjJ9mebhY1N90/VY+ouHwYcivUQRlz3zKdfEOPO9+uEeZP3hhddvljk3Ke0K9z8JgDTFQ== - dependencies: - "@sentry/types" "5.10.0-beta.3" - tslib "^1.9.3" - "@sinonjs/commons@^1", "@sinonjs/commons@^1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.4.0.tgz#7b3ec2d96af481d7a0321252e7b1c94724ec5a78" From dcf4c7f8f861e0df416c72726c6e330b3b49a04e Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Thu, 21 Nov 2019 10:17:40 +0100 Subject: [PATCH 53/63] meta: Cleanup --- packages/apm/src/hub.ts | 10 +++++++++- packages/apm/src/index.ts | 2 +- packages/apm/src/integrations/express.ts | 3 ++- packages/apm/src/integrations/tracing.ts | 6 ++---- packages/apm/src/integrations/transactionactivity.ts | 6 ++---- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/packages/apm/src/hub.ts b/packages/apm/src/hub.ts index 5084be50bf3b..d5af5cae6712 100644 --- a/packages/apm/src/hub.ts +++ b/packages/apm/src/hub.ts @@ -1,4 +1,4 @@ -import { Hub as BaseHub } from '@sentry/hub'; +import { getCurrentHub, Hub as BaseHub, makeMain } from '@sentry/hub'; import { Hub as BaseHubInterface, SpanContext } from '@sentry/types'; import { Span } from './span'; @@ -82,3 +82,11 @@ export class Hub extends BaseHub implements ApmHubInterface { return span; } } + +/** + * This will make the APM Hub the main one while maintaining the client and scope of the current hub + */ +export function makeApmHubMain(): void { + const hub = getCurrentHub(); + makeMain(new Hub(hub.getClient(), hub.getScope())); +} diff --git a/packages/apm/src/index.ts b/packages/apm/src/index.ts index 26bbaa9c7627..4d6082d3b611 100644 --- a/packages/apm/src/index.ts +++ b/packages/apm/src/index.ts @@ -1,5 +1,5 @@ import * as ApmIntegrations from './integrations'; -export { Hub } from './hub'; +export { Hub, makeApmHubMain as makeMain } from './hub'; export { ApmIntegrations as Integrations }; export { Span, TRACEPARENT_REGEXP } from './span'; diff --git a/packages/apm/src/integrations/express.ts b/packages/apm/src/integrations/express.ts index f58e5286e678..005f10d38757 100644 --- a/packages/apm/src/integrations/express.ts +++ b/packages/apm/src/integrations/express.ts @@ -3,7 +3,7 @@ import { logger } from '@sentry/utils'; // tslint:disable-next-line:no-implicit-dependencies import { Application, ErrorRequestHandler, NextFunction, Request, RequestHandler, Response } from 'express'; -import { Hub } from '../hub'; +import { Hub, makeApmHubMain } from '../hub'; /** * Express integration @@ -32,6 +32,7 @@ export class Express implements Integration { */ public constructor(options: { app?: Application } = {}) { this._app = options.app; + makeApmHubMain(); } /** diff --git a/packages/apm/src/integrations/tracing.ts b/packages/apm/src/integrations/tracing.ts index 6a72c8b81323..b3a9e0cb301d 100644 --- a/packages/apm/src/integrations/tracing.ts +++ b/packages/apm/src/integrations/tracing.ts @@ -1,8 +1,7 @@ -import { makeMain } from '@sentry/hub'; import { EventProcessor, Integration } from '@sentry/types'; import { fill, getGlobalObject, isMatchingPattern, logger, supportsNativeFetch } from '@sentry/utils'; -import { Hub } from '../hub'; +import { Hub, makeApmHubMain } from '../hub'; /** JSDoc */ interface TracingOptions { @@ -38,8 +37,7 @@ export class Tracing implements Integration { * @param _options TracingOptions */ public constructor(private readonly _options: TracingOptions = {}) { - // TODO - makeMain(new Hub()); + makeApmHubMain(); if (!Array.isArray(_options.tracingOrigins) || _options.tracingOrigins.length === 0) { const defaultTracingOrigins = ['localhost', /^\//]; logger.warn( diff --git a/packages/apm/src/integrations/transactionactivity.ts b/packages/apm/src/integrations/transactionactivity.ts index a26ac1bc5dad..47471521277e 100644 --- a/packages/apm/src/integrations/transactionactivity.ts +++ b/packages/apm/src/integrations/transactionactivity.ts @@ -1,8 +1,7 @@ -import { makeMain } from '@sentry/hub'; import { EventProcessor, Integration, Span, SpanContext } from '@sentry/types'; import { getGlobalObject } from '@sentry/utils'; -import { Hub } from '../hub'; +import { Hub, makeApmHubMain } from '../hub'; /** JSDoc */ interface TransactionActivityOptions { @@ -56,8 +55,7 @@ export class TransactionActivity implements Integration { * @inheritDoc */ public constructor(public readonly _options?: Partial) { - // TODO - makeMain(new Hub()); + makeApmHubMain(); const defaults = { idleTimeout: 500, startTransactionOnLocationChange: true, From 5116935ea27bafda5fcb75c0c3306855895cbf97 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Thu, 21 Nov 2019 11:29:31 +0100 Subject: [PATCH 54/63] feat: Refactor to use global extension hub method --- packages/apm/src/hub.ts | 92 ------------------- packages/apm/src/hubextensions.ts | 84 +++++++++++++++++ packages/apm/src/index.ts | 5 +- packages/apm/src/integrations/express.ts | 5 +- packages/apm/src/integrations/tracing.ts | 5 +- .../src/integrations/transactionactivity.ts | 5 +- packages/apm/src/span.ts | 4 +- packages/apm/test/hub.test.ts | 35 +++++++ packages/apm/test/span.test.ts | 4 +- packages/hub/src/hub.ts | 31 +++++++ packages/hub/src/interfaces.ts | 4 + packages/hub/test/global.test.ts | 17 +++- packages/hub/test/hub.test.ts | 22 ----- packages/hub/test/scope.test.ts | 6 +- packages/node/src/handlers.ts | 37 ++++---- packages/node/src/integrations/http.ts | 16 +--- packages/types/src/hub.ts | 13 +++ 17 files changed, 219 insertions(+), 166 deletions(-) delete mode 100644 packages/apm/src/hub.ts create mode 100644 packages/apm/src/hubextensions.ts create mode 100644 packages/apm/test/hub.test.ts diff --git a/packages/apm/src/hub.ts b/packages/apm/src/hub.ts deleted file mode 100644 index d5af5cae6712..000000000000 --- a/packages/apm/src/hub.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { getCurrentHub, Hub as BaseHub, makeMain } from '@sentry/hub'; -import { Hub as BaseHubInterface, SpanContext } from '@sentry/types'; - -import { Span } from './span'; - -/** - * Checks whether given value is instance of Span - * @param span value to check - */ -function isSpanInstance(span: unknown): span is Span { - return span instanceof Span; -} - -/** - * Hub with APM extension methods - */ -export interface ApmHubInterface extends BaseHubInterface { - /** Returns all trace headers that are currently on the top scope. */ - traceHeaders(): { [key: string]: string }; - - /** - * This functions starts a span. If argument passed is of type `Span`, it'll run sampling on it if configured - * and attach a `SpanRecorder`. If it's of type `SpanContext` and there is already a `Span` on the Scope, - * the created Span will have a reference to it and become it's child. Otherwise it'll crete a new `Span`. - * - * @param span Already constructed span which should be started or properties with which the span should be created - */ - startSpan(span?: Span | SpanContext, forceNoChild?: boolean): Span; -} - -/** - * APM Hub - */ -export class Hub extends BaseHub implements ApmHubInterface { - /** - * @inheritDoc - */ - public traceHeaders(): { [key: string]: string } { - const scope = this.getScope(); - if (scope) { - const span = scope.getSpan(); - if (span) { - return { - 'sentry-trace': span.toTraceparent(), - }; - } - } - return {}; - } - - /** - * @inheritDoc - */ - public startSpan(spanOrSpanContext?: Span | SpanContext, forceNoChild: boolean = false): Span { - const scope = this.getScope(); - const client = this.getClient(); - let span; - - if (!isSpanInstance(spanOrSpanContext) && !forceNoChild) { - if (scope) { - const parentSpan = scope.getSpan() as Span; - if (parentSpan) { - span = parentSpan.child(spanOrSpanContext); - } - } - } - - if (!isSpanInstance(span)) { - span = new Span(spanOrSpanContext, this); - } - - if (span.sampled === undefined && span.transaction !== undefined) { - const sampleRate = (client && client.getOptions().tracesSampleRate) || 0; - span.sampled = Math.random() < sampleRate; - } - - if (span.sampled) { - const experimentsOptions = (client && client.getOptions()._experiments) || {}; - span.initFinishedSpans(experimentsOptions.maxSpans); - } - - return span; - } -} - -/** - * This will make the APM Hub the main one while maintaining the client and scope of the current hub - */ -export function makeApmHubMain(): void { - const hub = getCurrentHub(); - makeMain(new Hub(hub.getClient(), hub.getScope())); -} diff --git a/packages/apm/src/hubextensions.ts b/packages/apm/src/hubextensions.ts new file mode 100644 index 000000000000..e759aacb9ff4 --- /dev/null +++ b/packages/apm/src/hubextensions.ts @@ -0,0 +1,84 @@ +import { getMainCarrier, Hub } from '@sentry/hub'; +import { SpanContext } from '@sentry/types'; + +import { Span } from './span'; + +/** + * Checks whether given value is instance of Span + * @param span value to check + */ +function isSpanInstance(span: unknown): span is Span { + return span instanceof Span; +} + +/** Returns all trace headers that are currently on the top scope. */ +function traceHeaders(): { [key: string]: string } { + // @ts-ignore + const that = this as Hub; + const scope = that.getScope(); + if (scope) { + const span = scope.getSpan(); + if (span) { + return { + 'sentry-trace': span.toTraceparent(), + }; + } + } + return {}; +} + +/** + * This functions starts a span. If argument passed is of type `Span`, it'll run sampling on it if configured + * and attach a `SpanRecorder`. If it's of type `SpanContext` and there is already a `Span` on the Scope, + * the created Span will have a reference to it and become it's child. Otherwise it'll crete a new `Span`. + * + * @param span Already constructed span which should be started or properties with which the span should be created + */ +function startSpan(spanOrSpanContext?: Span | SpanContext, forceNoChild: boolean = false): Span { + // @ts-ignore + const that = this as Hub; + const scope = that.getScope(); + const client = that.getClient(); + let span; + + if (!isSpanInstance(spanOrSpanContext) && !forceNoChild) { + if (scope) { + const parentSpan = scope.getSpan() as Span; + if (parentSpan) { + span = parentSpan.child(spanOrSpanContext); + } + } + } + + if (!isSpanInstance(span)) { + span = new Span(spanOrSpanContext, that); + } + + if (span.sampled === undefined && span.transaction !== undefined) { + const sampleRate = (client && client.getOptions().tracesSampleRate) || 0; + span.sampled = Math.random() < sampleRate; + } + + if (span.sampled) { + const experimentsOptions = (client && client.getOptions()._experiments) || {}; + span.initFinishedSpans(experimentsOptions.maxSpans); + } + + return span; +} + +/** + * This patches the global object and injects the APM extensions methods + */ +export function addExtensionMethods(): void { + const carrier = getMainCarrier(); + if (carrier.__SENTRY__) { + carrier.__SENTRY__.extensions = carrier.__SENTRY__.extensions || {}; + if (!carrier.__SENTRY__.extensions.startSpan) { + carrier.__SENTRY__.extensions.startSpan = startSpan; + } + if (!carrier.__SENTRY__.extensions.traceHeaders) { + carrier.__SENTRY__.extensions.traceHeaders = traceHeaders; + } + } +} diff --git a/packages/apm/src/index.ts b/packages/apm/src/index.ts index 4d6082d3b611..301dbc7fd38a 100644 --- a/packages/apm/src/index.ts +++ b/packages/apm/src/index.ts @@ -1,5 +1,8 @@ +import { addExtensionMethods } from './hubextensions'; import * as ApmIntegrations from './integrations'; -export { Hub, makeApmHubMain as makeMain } from './hub'; export { ApmIntegrations as Integrations }; export { Span, TRACEPARENT_REGEXP } from './span'; + +// We are patching the global object with our hub extension methods +addExtensionMethods(); diff --git a/packages/apm/src/integrations/express.ts b/packages/apm/src/integrations/express.ts index 005f10d38757..1caa3f681390 100644 --- a/packages/apm/src/integrations/express.ts +++ b/packages/apm/src/integrations/express.ts @@ -1,10 +1,8 @@ -import { EventProcessor, Integration } from '@sentry/types'; +import { EventProcessor, Hub, Integration } from '@sentry/types'; import { logger } from '@sentry/utils'; // tslint:disable-next-line:no-implicit-dependencies import { Application, ErrorRequestHandler, NextFunction, Request, RequestHandler, Response } from 'express'; -import { Hub, makeApmHubMain } from '../hub'; - /** * Express integration * @@ -32,7 +30,6 @@ export class Express implements Integration { */ public constructor(options: { app?: Application } = {}) { this._app = options.app; - makeApmHubMain(); } /** diff --git a/packages/apm/src/integrations/tracing.ts b/packages/apm/src/integrations/tracing.ts index b3a9e0cb301d..2619c209371f 100644 --- a/packages/apm/src/integrations/tracing.ts +++ b/packages/apm/src/integrations/tracing.ts @@ -1,8 +1,6 @@ -import { EventProcessor, Integration } from '@sentry/types'; +import { EventProcessor, Hub, Integration } from '@sentry/types'; import { fill, getGlobalObject, isMatchingPattern, logger, supportsNativeFetch } from '@sentry/utils'; -import { Hub, makeApmHubMain } from '../hub'; - /** JSDoc */ interface TracingOptions { tracingOrigins?: Array; @@ -37,7 +35,6 @@ export class Tracing implements Integration { * @param _options TracingOptions */ public constructor(private readonly _options: TracingOptions = {}) { - makeApmHubMain(); if (!Array.isArray(_options.tracingOrigins) || _options.tracingOrigins.length === 0) { const defaultTracingOrigins = ['localhost', /^\//]; logger.warn( diff --git a/packages/apm/src/integrations/transactionactivity.ts b/packages/apm/src/integrations/transactionactivity.ts index 47471521277e..7bd730ac2651 100644 --- a/packages/apm/src/integrations/transactionactivity.ts +++ b/packages/apm/src/integrations/transactionactivity.ts @@ -1,8 +1,6 @@ -import { EventProcessor, Integration, Span, SpanContext } from '@sentry/types'; +import { EventProcessor, Hub, Integration, Span, SpanContext } from '@sentry/types'; import { getGlobalObject } from '@sentry/utils'; -import { Hub, makeApmHubMain } from '../hub'; - /** JSDoc */ interface TransactionActivityOptions { idleTimeout: number; @@ -55,7 +53,6 @@ export class TransactionActivity implements Integration { * @inheritDoc */ public constructor(public readonly _options?: Partial) { - makeApmHubMain(); const defaults = { idleTimeout: 500, startTransactionOnLocationChange: true, diff --git a/packages/apm/src/span.ts b/packages/apm/src/span.ts index 473a2f8750b1..f899a57a07de 100644 --- a/packages/apm/src/span.ts +++ b/packages/apm/src/span.ts @@ -1,11 +1,9 @@ // tslint:disable:max-classes-per-file -import { getCurrentHub } from '@sentry/hub'; +import { getCurrentHub, Hub } from '@sentry/hub'; import { Span as SpanInterface, SpanContext } from '@sentry/types'; import { logger, timestampWithMs, uuid4 } from '@sentry/utils'; -import { Hub } from './hub'; - export const TRACEPARENT_REGEXP = new RegExp( '^[ \\t]*' + // whitespace '([0-9a-f]{32})?' + // trace_id diff --git a/packages/apm/test/hub.test.ts b/packages/apm/test/hub.test.ts new file mode 100644 index 000000000000..d6873ec2f53d --- /dev/null +++ b/packages/apm/test/hub.test.ts @@ -0,0 +1,35 @@ +import { Hub, Scope } from '@sentry/hub'; + +import { addExtensionMethods } from '../src/hubextensions'; + +addExtensionMethods(); +const clientFn: any = jest.fn(); + +describe('Hub', () => { + afterEach(() => { + jest.resetAllMocks(); + jest.useRealTimers(); + }); + + describe('spans', () => { + describe('start', () => { + test('simple', () => { + const hub = new Hub(clientFn); + const span = hub.startSpan() as any; + expect(span._spanId).toBeTruthy(); + }); + + test('inherits from parent span', () => { + const myScope = new Scope(); + const hub = new Hub(clientFn, myScope); + const parentSpan = hub.startSpan({}) as any; + expect(parentSpan._parentId).toBeFalsy(); + hub.configureScope(scope => { + scope.setSpan(parentSpan); + }); + const span = hub.startSpan({}) as any; + expect(span._parentSpanId).toBeTruthy(); + }); + }); + }); +}); diff --git a/packages/apm/test/span.test.ts b/packages/apm/test/span.test.ts index 2edced5a2711..da3b3dbeac42 100644 --- a/packages/apm/test/span.test.ts +++ b/packages/apm/test/span.test.ts @@ -1,6 +1,6 @@ -import { Scope } from '@sentry/hub'; +import { Hub, Scope } from '@sentry/hub'; -import { Hub, Span, TRACEPARENT_REGEXP } from '../src'; +import { Span, TRACEPARENT_REGEXP } from '../src'; describe('Span', () => { let hub: Hub; diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index 27ff474fc18e..cba7bd59dc08 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -8,6 +8,8 @@ import { Integration, IntegrationClass, Severity, + Span, + SpanContext, User, } from '@sentry/types'; import { @@ -375,12 +377,41 @@ export class Hub implements HubInterface { return null; } } + + /** + * @inheritdoc + */ + public startSpan(spanOrSpanContext?: Span | SpanContext, forceNoChild: boolean = false): Span { + return this._callExtensionMethod('startSpan', spanOrSpanContext, forceNoChild); + } + + /** + * @inheritdoc + */ + public traceHeaders(): { [key: string]: string } { + return this._callExtensionMethod<{ [key: string]: string }>('traceHeaders'); + } + + /** + * Calls global extension method and binding current instance to the function call + */ + // @ts-ignore + private _callExtensionMethod(method: string, ...args: any[]): T { + const carrier = getMainCarrier(); + const sentry = carrier.__SENTRY__; + // tslint:disable-next-line: strict-type-predicates + if (sentry && sentry.extensions && typeof sentry.extensions[method] === 'function') { + return sentry.extensions[method].apply(this, args); + } + logger.warn(`Extension method ${method} couldn't be found, doing nothing.`); + } } /** Returns the global shim registry. */ export function getMainCarrier(): Carrier { const carrier = getGlobalObject(); carrier.__SENTRY__ = carrier.__SENTRY__ || { + extensions: {}, hub: undefined, }; return carrier; diff --git a/packages/hub/src/interfaces.ts b/packages/hub/src/interfaces.ts index 644d77431688..529389aaf915 100644 --- a/packages/hub/src/interfaces.ts +++ b/packages/hub/src/interfaces.ts @@ -19,5 +19,9 @@ export interface Layer { export interface Carrier { __SENTRY__?: { hub?: Hub; + /** + * These are extension methods for the hub, the current instance of the hub will be bound to it + */ + extensions?: { [key: string]: Function }; }; } diff --git a/packages/hub/test/global.test.ts b/packages/hub/test/global.test.ts index 986f62e42b64..069c992d1c2d 100644 --- a/packages/hub/test/global.test.ts +++ b/packages/hub/test/global.test.ts @@ -15,8 +15,23 @@ describe('global', () => { }); test('getGlobalHub', () => { - const newestHub = new Hub(undefined, [], 999999); + const newestHub = new Hub(undefined, undefined, 999999); (global as any).__SENTRY__.hub = newestHub; expect(getCurrentHub()).toBe(newestHub); }); + + test('hub extension methods receive correct hub instance', () => { + const newestHub = new Hub(undefined, undefined, 999999); + (global as any).__SENTRY__.hub = newestHub; + // tslint:disable-next-line: typedef + const fn = jest.fn().mockImplementation(function(...args: []) { + expect(this).toBe(newestHub); + expect(args).toEqual([1, 2, 3]); + }); + (global as any).__SENTRY__.extensions = {}; + (global as any).__SENTRY__.extensions.testy = fn; + (getCurrentHub() as any)._callExtensionMethod('testy', 1, 2, 3); + expect(fn).toBeCalled(); + }); + // (global as any).__SENTRY__ }); diff --git a/packages/hub/test/hub.test.ts b/packages/hub/test/hub.test.ts index 9f83885f13ed..f42e0f631428 100644 --- a/packages/hub/test/hub.test.ts +++ b/packages/hub/test/hub.test.ts @@ -281,26 +281,4 @@ describe('Hub', () => { }); }); }); - - describe('spans', () => { - describe('start', () => { - test('simple', () => { - const hub = new Hub(clientFn); - const span = hub.startSpan() as any; - expect(span._spanId).toBeTruthy(); - }); - - test('inherits from parent span', () => { - const myScope = new Scope(); - const hub = new Hub(clientFn, myScope); - const parentSpan = hub.startSpan({}) as any; - expect(parentSpan._parentId).toBeFalsy(); - hub.configureScope(scope => { - scope.setSpan(parentSpan); - }); - const span = hub.startSpan({}) as any; - expect(span._parentSpanId).toBeTruthy(); - }); - }); - }); }); diff --git a/packages/hub/test/scope.test.ts b/packages/hub/test/scope.test.ts index 5befadbefc39..df866e1de44d 100644 --- a/packages/hub/test/scope.test.ts +++ b/packages/hub/test/scope.test.ts @@ -1,7 +1,7 @@ import { Event, EventHint, Severity } from '@sentry/types'; import { getGlobalObject } from '@sentry/utils'; -import { addGlobalEventProcessor, Scope, Span } from '../src'; +import { addGlobalEventProcessor, Scope } from '../src'; describe('Scope', () => { afterEach(() => { @@ -111,13 +111,13 @@ describe('Scope', () => { describe('span', () => { test('set', () => { const scope = new Scope(); - const span = new Span({}); + const span = { fake: 'span' } as any; scope.setSpan(span); expect((scope as any)._span).toEqual(span); }); test('unset', () => { const scope = new Scope(); - scope.setSpan(new Span({})); + scope.setSpan({ fake: 'span' } as any); scope.setSpan(); expect((scope as any)._span).toEqual(undefined); }); diff --git a/packages/node/src/handlers.ts b/packages/node/src/handlers.ts index bbdd834668c1..50294f60c896 100644 --- a/packages/node/src/handlers.ts +++ b/packages/node/src/handlers.ts @@ -1,4 +1,4 @@ -import { Hub, Span } from '@sentry/apm'; +import { Span } from '@sentry/apm'; import { captureException, getCurrentHub, withScope } from '@sentry/core'; import { Event } from '@sentry/types'; import { forget, isString, logger, normalize } from '@sentry/utils'; @@ -31,24 +31,23 @@ export function tracingHandler(): ( // but `req.path` or `req.url` should do the job as well. We could unify this here. const reqMethod = (req.method || '').toUpperCase(); const reqUrl = req.url; - // TODO - const hub = (getCurrentHub() as unknown) as Hub; - if (hub.startSpan) { - const transaction = hub.startSpan({ - transaction: `${reqMethod}|${reqUrl}`, - }); - hub.configureScope(scope => { - scope.setSpan(transaction); - }); - res.once('finish', () => { - if (res.statusCode >= 500) { - transaction.setFailure(); - } else { - transaction.setSuccess(); - } - transaction.finish(); - }); - } + + const hub = getCurrentHub(); + const transaction = hub.startSpan({ + transaction: `${reqMethod}|${reqUrl}`, + }); + hub.configureScope(scope => { + scope.setSpan(transaction); + }); + res.once('finish', () => { + if (res.statusCode >= 500) { + transaction.setFailure(); + } else { + transaction.setSuccess(); + } + transaction.finish(); + }); + next(); }; } diff --git a/packages/node/src/integrations/http.ts b/packages/node/src/integrations/http.ts index 3d0068526333..d3350e701e32 100644 --- a/packages/node/src/integrations/http.ts +++ b/packages/node/src/integrations/http.ts @@ -1,6 +1,4 @@ -import { Hub } from '@sentry/apm'; import { getCurrentHub } from '@sentry/core'; -import { makeMain } from '@sentry/hub'; import { Integration, Span } from '@sentry/types'; import { fill, parseSemver } from '@sentry/utils'; import * as http from 'http'; @@ -33,8 +31,6 @@ export class Http implements Integration { * @inheritDoc */ public constructor(options: { breadcrumbs?: boolean; tracing?: boolean } = {}) { - // TODO - makeMain(new Hub()); this._breadcrumbs = typeof options.breadcrumbs === 'undefined' ? true : options.breadcrumbs; this._tracing = typeof options.tracing === 'undefined' ? false : options.tracing; } @@ -85,13 +81,11 @@ function createHandlerWrapper( let span: Span; if (tracingEnabled) { // TODO - const hub = (getCurrentHub() as unknown) as Hub; - if (hub.startSpan) { - span = hub.startSpan({ - description: `${typeof options === 'string' || !options.method ? 'GET' : options.method}|${requestUrl}`, - op: 'request', - }); - } + const hub = getCurrentHub(); + span = hub.startSpan({ + description: `${typeof options === 'string' || !options.method ? 'GET' : options.method}|${requestUrl}`, + op: 'request', + }); } return originalHandler diff --git a/packages/types/src/hub.ts b/packages/types/src/hub.ts index a22d9df988b3..ccc8fa410e9a 100644 --- a/packages/types/src/hub.ts +++ b/packages/types/src/hub.ts @@ -4,6 +4,7 @@ import { Event, EventHint } from './event'; import { Integration, IntegrationClass } from './integration'; import { Scope } from './scope'; import { Severity } from './severity'; +import { Span, SpanContext } from './span'; import { User } from './user'; /** @@ -167,4 +168,16 @@ export interface Hub { /** Returns the integration if installed on the current client. */ getIntegration(integration: IntegrationClass): T | null; + + /** Returns all trace headers that are currently on the top scope. */ + traceHeaders(): { [key: string]: string }; + + /** + * This functions starts a span. If argument passed is of type `Span`, it'll run sampling on it if configured + * and attach a `SpanRecorder`. If it's of type `SpanContext` and there is already a `Span` on the Scope, + * the created Span will have a reference to it and become it's child. Otherwise it'll crete a new `Span`. + * + * @param span Already constructed span which should be started or properties with which the span should be created + */ + startSpan(span?: Span | SpanContext, forceNoChild?: boolean): Span; } From 856dbd5f6184ca757d9a51e76a3ca46475b408d8 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Thu, 21 Nov 2019 15:34:34 +0100 Subject: [PATCH 55/63] ref: Move code into tracing integration --- packages/apm/src/integrations/index.ts | 3 +- packages/apm/src/integrations/tracing.ts | 356 +++++++++++++++++- .../src/integrations/transactionactivity.ts | 347 ----------------- ...actionactivity.test.ts => tracing.test.ts} | 22 +- 4 files changed, 353 insertions(+), 375 deletions(-) delete mode 100644 packages/apm/src/integrations/transactionactivity.ts rename packages/apm/test/{transactionactivity.test.ts => tracing.test.ts} (69%) diff --git a/packages/apm/src/integrations/index.ts b/packages/apm/src/integrations/index.ts index 035440a364b0..3c10eab68153 100644 --- a/packages/apm/src/integrations/index.ts +++ b/packages/apm/src/integrations/index.ts @@ -1,3 +1,2 @@ export { Express } from './express'; -export { Tracing } from './tracing'; -export { TransactionActivity, TransactionActivityHandlers } from './transactionactivity'; +export { Tracing, TracingHandlers } from './tracing'; diff --git a/packages/apm/src/integrations/tracing.ts b/packages/apm/src/integrations/tracing.ts index 2619c209371f..ebf7db362c03 100644 --- a/packages/apm/src/integrations/tracing.ts +++ b/packages/apm/src/integrations/tracing.ts @@ -1,13 +1,24 @@ -import { EventProcessor, Hub, Integration } from '@sentry/types'; +import { EventProcessor, Hub, Integration, Span, SpanContext } from '@sentry/types'; import { fill, getGlobalObject, isMatchingPattern, logger, supportsNativeFetch } from '@sentry/utils'; /** JSDoc */ interface TracingOptions { - tracingOrigins?: Array; - traceFetch?: boolean; - traceXHR?: boolean; + tracingOrigins: Array; + traceFetch: boolean; + traceXHR: boolean; + idleTimeout: number; + startTransactionOnLocationChange: boolean; + tracesSampleRate: number; } +/** JSDoc */ +interface Activity { + name: string; + span?: Span; +} + +const global = getGlobalObject(); + /** * Tracing Integration */ @@ -29,32 +40,80 @@ export class Tracing implements Integration { // @ts-ignore private _xhrUrl?: string; + /** + * Is Tracing enabled, this will be determined once per pageload. + */ + private static _enabled?: boolean; + + /** JSDoc */ + public static options: TracingOptions; + + /** + * Returns current hub. + */ + private static _getCurrentHub?: () => Hub; + + private static _activeTransaction?: Span; + + private static _currentIndex: number = 0; + + private static readonly _activities: { [key: number]: Activity } = {}; + + private static _debounce: number = 0; + /** * Constructor for Tracing * * @param _options TracingOptions */ - public constructor(private readonly _options: TracingOptions = {}) { - if (!Array.isArray(_options.tracingOrigins) || _options.tracingOrigins.length === 0) { - const defaultTracingOrigins = ['localhost', /^\//]; + public constructor(private readonly _options?: Partial) { + const defaultTracingOrigins = ['localhost', /^\//]; + const defaults = { + idleTimeout: 500, + startTransactionOnLocationChange: true, + traceFetch: true, + traceXHR: true, + tracesSampleRate: 1, + tracingOrigins: defaultTracingOrigins, + }; + if (!_options || !Array.isArray(_options.tracingOrigins) || _options.tracingOrigins.length === 0) { logger.warn( 'Sentry: You need to define `tracingOrigins` in the options. Set an array of urls or patterns to trace.', ); logger.warn(`Sentry: We added a reasonable default for you: ${defaultTracingOrigins}`); - _options.tracingOrigins = defaultTracingOrigins; } + Tracing.options = this._options = { + ...defaults, + ..._options, + }; } /** * @inheritDoc */ public setupOnce(_: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void { - if (this._options.traceXHR !== false) { + Tracing._getCurrentHub = getCurrentHub; + + if (!Tracing._isEnabled()) { + return; + } + + // tslint:disable-next-line: no-non-null-assertion + if (this._options!.traceXHR !== false) { this._traceXHR(getCurrentHub); } - if (this._options.traceFetch !== false) { + // tslint:disable-next-line: no-non-null-assertion + if (this._options!.traceFetch !== false) { this._traceFetch(getCurrentHub); } + + if (global.location && global.location.href) { + // `${global.location.href}` will be used a temp transaction name + Tracing.startIdleTransaction(global.location.href, { + op: 'pageload', + sampled: true, + }); + } } /** @@ -89,11 +148,12 @@ export class Tracing implements Integration { function(this: XMLHttpRequest, ...args: any[]): void { // @ts-ignore const self = getCurrentHub().getIntegration(Tracing); - if (self && self._xhrUrl && self._options.tracingOrigins) { + // tslint:disable-next-line: no-non-null-assertion + if (self && self._xhrUrl && self._options!.tracingOrigins) { const url = self._xhrUrl; const headers = getCurrentHub().traceHeaders(); - // tslint:disable-next-line: prefer-for-of - let isWhitelisted = self._options.tracingOrigins.some((origin: string | RegExp) => + // tslint:disable-next-line: prefer-for-of no-non-null-assertion + let isWhitelisted = self._options!.tracingOrigins.some((origin: string | RegExp) => isMatchingPattern(url, origin), ); @@ -129,12 +189,14 @@ export class Tracing implements Integration { // @ts-ignore const hub = getCurrentHub(); const self = hub.getIntegration(Tracing); - if (self && self._options.tracingOrigins) { + // tslint:disable-next-line: no-non-null-assertion + if (self && self._options!.tracingOrigins) { const url = args[0] as string; const options = (args[1] = (args[1] as { [key: string]: any }) || {}); let isWhitelisted = false; - self._options.tracingOrigins.forEach((whiteListUrl: string | RegExp) => { + // tslint:disable-next-line: no-non-null-assertion + self._options!.tracingOrigins.forEach((whiteListUrl: string | RegExp) => { if (!isWhitelisted) { isWhitelisted = isMatchingPattern(url, whiteListUrl); } @@ -167,4 +229,268 @@ export class Tracing implements Integration { }); // tslint:enable: only-arrow-functions } + + /** + * Is tracing enabled + */ + private static _isEnabled(): boolean { + if (Tracing._enabled !== undefined) { + return Tracing._enabled; + } + // This happens only in test cases where the integration isn't initalized properly + // tslint:disable-next-line: strict-type-predicates + if (!Tracing.options || typeof Tracing.options.tracesSampleRate !== 'number') { + return false; + } + Tracing._enabled = Math.random() > Tracing.options.tracesSampleRate ? false : true; + return Tracing._enabled; + } + + /** + * Starts a Transaction waiting for activity idle to finish + */ + public static startIdleTransaction(name: string, spanContext?: SpanContext): Span | undefined { + if (!Tracing._isEnabled()) { + // Tracing is not enabled + return undefined; + } + + const activeTransaction = Tracing._activeTransaction; + + if (activeTransaction) { + // If we already have an active transaction it means one of two things + // a) The user did rapid navigation changes and didn't wait until the transaction was finished + // b) A activity wasn't popped correctly and therefore the transaction is stalling + activeTransaction.finish(); + } + + const _getCurrentHub = Tracing._getCurrentHub; + if (!_getCurrentHub) { + return undefined; + } + + const hub = _getCurrentHub(); + if (!hub) { + return undefined; + } + + const span = hub.startSpan( + { + ...spanContext, + transaction: name, + }, + true, + ); + + Tracing._activeTransaction = span; + + // We need to do this workaround here and not use configureScope + // Reason being at the time we start the inital transaction we do not have a client bound on the hub yet + // therefore configureScope wouldn't be executed and we would miss setting the transaction + // tslint:disable-next-line: no-unsafe-any + (hub as any).getScope().setSpan(span); + + // The reason we do this here is because of cached responses + // If we start and transaction without an activity it would never finish since there is no activity + const id = Tracing.pushActivity('idleTransactionStarted'); + setTimeout(() => { + Tracing.popActivity(id); + }, (Tracing.options && Tracing.options.idleTimeout) || 100); + + return span; + } + + /** + * Update transaction + */ + public static updateTransactionName(name: string): void { + const activeTransaction = Tracing._activeTransaction; + if (!activeTransaction) { + return; + } + // TODO + (activeTransaction as any).transaction = name; + } + + /** + * Finshes the current active transaction + */ + public static finishIdleTransaction(): void { + const active = Tracing._activeTransaction; + if (active) { + // true = use timestamp of last span + active.finish(true); + } + } + + /** + * Starts tracking for a specifc activity + */ + public static pushActivity(name: string, spanContext?: SpanContext): number { + if (!Tracing._isEnabled()) { + // Tracing is not enabled + return 0; + } + + // We want to clear the timeout also here since we push a new activity + clearTimeout(Tracing._debounce); + + const _getCurrentHub = Tracing._getCurrentHub; + if (spanContext && _getCurrentHub) { + const hub = _getCurrentHub(); + if (hub) { + Tracing._activities[Tracing._currentIndex] = { + name, + span: hub.startSpan(spanContext), + }; + } + } else { + Tracing._activities[Tracing._currentIndex] = { + name, + }; + } + + return Tracing._currentIndex++; + } + + /** + * Removes activity and finishes the span in case there is one + */ + public static popActivity(id: number, spanData?: { [key: string]: any }): void { + if (!Tracing._isEnabled()) { + // Tracing is not enabled + return; + } + + const activity = Tracing._activities[id]; + if (activity) { + const span = activity.span; + if (span) { + if (spanData) { + Object.keys(spanData).forEach((key: string) => { + span.setData(key, spanData[key]); + }); + } + span.finish(); + } + // tslint:disable-next-line: no-dynamic-delete + delete Tracing._activities[id]; + } + + const count = Object.keys(Tracing._activities).length; + clearTimeout(Tracing._debounce); + + if (count === 0) { + const timeout = Tracing.options && Tracing.options.idleTimeout; + Tracing._debounce = (setTimeout(() => { + Tracing.finishIdleTransaction(); + }, timeout) as any) as number; + } + } } + +/** + * Creates breadcrumbs from XHR API calls + */ +function xhrCallback(handlerData: { [key: string]: any }): void { + // tslint:disable: no-unsafe-any + if (handlerData.requestComplete && handlerData.xhr.__sentry_xhr_activity_id__) { + Tracing.popActivity(handlerData.xhr.__sentry_xhr_activity_id__, handlerData.xhr.__sentry_xhr__); + return; + } + // We only capture complete, non-sentry requests + if (handlerData.xhr.__sentry_own_request__) { + return; + } + + const xhr = handlerData.xhr.__sentry_xhr__; + handlerData.xhr.__sentry_xhr_activity_id__ = Tracing.pushActivity('xhr', { + data: { + request_data: xhr.data, + }, + description: `${xhr.method} ${xhr.url}`, + op: 'http', + }); + // tslint:enable: no-unsafe-any +} + +/** + * Creates breadcrumbs from fetch API calls + */ +// function fetchHandler(handlerData: { [key: string]: any }): void { +// // We only capture complete fetch requests +// if (!handlerData.requestComplete) { +// return; +// } + +// const client = getCurrentHub().getClient(); +// const dsn = client && client.getDsn(); + +// if (dsn) { +// const filterUrl = new API(dsn).getStoreEndpoint(); +// // if Sentry key appears in URL, don't capture it as a request +// // but rather as our own 'sentry' type breadcrumb +// if ( +// filterUrl && +// handlerData.fetchData.url.indexOf(filterUrl) !== -1 && +// handlerData.fetchData.method === 'POST' && +// handlerData.args[1] && +// handlerData.args[1].body +// ) { +// addSentryBreadcrumb(handlerData.args[1].body); +// return; +// } +// } + +// if (handlerData.error) { +// getCurrentHub().addBreadcrumb( +// { +// category: 'fetch', +// data: handlerData.fetchData, +// level: Severity.Error, +// type: 'http', +// }, +// { +// data: handlerData.error, +// input: handlerData.args, +// }, +// ); +// } else { +// getCurrentHub().addBreadcrumb( +// { +// category: 'fetch', +// data: handlerData.fetchData, +// type: 'http', +// }, +// { +// input: handlerData.args, +// response: handlerData.response, +// }, +// ); +// } +// } + +/** + * Creates transaction from navigation changes + */ +function historyCallback(_: { [key: string]: any }): void { + if (Tracing.options.startTransactionOnLocationChange && global && global.location) { + Tracing.startIdleTransaction(global.location.href, { + op: 'navigation', + sampled: true, + }); + } +} + +const historyHandler = { + callback: historyCallback, + type: 'history', +}; + +const xhrHandler = { + callback: xhrCallback, + type: 'xhr', +}; + +// tslint:disable-next-line: variable-name +export const TracingHandlers = [historyHandler, xhrHandler]; diff --git a/packages/apm/src/integrations/transactionactivity.ts b/packages/apm/src/integrations/transactionactivity.ts deleted file mode 100644 index 7bd730ac2651..000000000000 --- a/packages/apm/src/integrations/transactionactivity.ts +++ /dev/null @@ -1,347 +0,0 @@ -import { EventProcessor, Hub, Integration, Span, SpanContext } from '@sentry/types'; -import { getGlobalObject } from '@sentry/utils'; - -/** JSDoc */ -interface TransactionActivityOptions { - idleTimeout: number; - startTransactionOnLocationChange: boolean; - tracesSampleRate: number; -} - -/** JSDoc */ -interface Activity { - name: string; - span?: Span; -} - -const global = getGlobalObject(); - -/** JSDoc */ -export class TransactionActivity implements Integration { - /** - * @inheritDoc - */ - public name: string = TransactionActivity.id; - - /** - * @inheritDoc - */ - public static id: string = 'TransactionActivity'; - - /** - * Is Tracing enabled, this will be determined once per pageload. - */ - private static _enabled?: boolean; - - /** JSDoc */ - public static options: TransactionActivityOptions; - - /** - * Returns current hub. - */ - private static _getCurrentHub?: () => Hub; - - private static _activeTransaction?: Span; - - private static _currentIndex: number = 0; - - private static readonly _activities: { [key: number]: Activity } = {}; - - private static _debounce: number = 0; - - /** - * @inheritDoc - */ - public constructor(public readonly _options?: Partial) { - const defaults = { - idleTimeout: 500, - startTransactionOnLocationChange: true, - tracesSampleRate: 1, - }; - TransactionActivity.options = { - ...defaults, - ..._options, - }; - } - - /** - * @inheritDoc - */ - public setupOnce(_: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void { - TransactionActivity._getCurrentHub = getCurrentHub; - if (!TransactionActivity._isEnabled()) { - return; - } - if (global.location && global.location.href) { - // `${global.location.href}` will be used a temp transaction name - TransactionActivity.startIdleTransaction(global.location.href, { - op: 'pageload', - sampled: true, - }); - } - } - - /** - * Is tracing enabled - */ - private static _isEnabled(): boolean { - if (TransactionActivity._enabled !== undefined) { - return TransactionActivity._enabled; - } - // This happens only in test cases where the integration isn't initalized properly - // tslint:disable-next-line: strict-type-predicates - if (!TransactionActivity.options || typeof TransactionActivity.options.tracesSampleRate !== 'number') { - return false; - } - TransactionActivity._enabled = Math.random() > TransactionActivity.options.tracesSampleRate ? false : true; - return TransactionActivity._enabled; - } - - /** - * Starts a Transaction waiting for activity idle to finish - */ - public static startIdleTransaction(name: string, spanContext?: SpanContext): Span | undefined { - if (!TransactionActivity._isEnabled()) { - // Tracing is not enabled - return undefined; - } - - const activeTransaction = TransactionActivity._activeTransaction; - - if (activeTransaction) { - // If we already have an active transaction it means one of two things - // a) The user did rapid navigation changes and didn't wait until the transaction was finished - // b) A activity wasn't popped correctly and therefore the transaction is stalling - activeTransaction.finish(); - } - - const _getCurrentHub = TransactionActivity._getCurrentHub; - if (!_getCurrentHub) { - return undefined; - } - - const hub = _getCurrentHub(); - if (!hub) { - return undefined; - } - - const span = hub.startSpan( - { - ...spanContext, - transaction: name, - }, - true, - ); - - TransactionActivity._activeTransaction = span; - - // We need to do this workaround here and not use configureScope - // Reason being at the time we start the inital transaction we do not have a client bound on the hub yet - // therefore configureScope wouldn't be executed and we would miss setting the transaction - // tslint:disable-next-line: no-unsafe-any - (hub as any).getScope().setSpan(span); - - // The reason we do this here is because of cached responses - // If we start and transaction without an activity it would never finish since there is no activity - const id = TransactionActivity.pushActivity('idleTransactionStarted'); - setTimeout(() => { - TransactionActivity.popActivity(id); - }, (TransactionActivity.options && TransactionActivity.options.idleTimeout) || 100); - - return span; - } - - /** - * Update transaction - */ - public static updateTransactionName(name: string): void { - const activeTransaction = TransactionActivity._activeTransaction; - if (!activeTransaction) { - return; - } - // TODO - (activeTransaction as any).transaction = name; - } - - /** - * Finshes the current active transaction - */ - public static finishIdleTransaction(): void { - const active = TransactionActivity._activeTransaction; - if (active) { - // true = use timestamp of last span - active.finish(true); - } - } - - /** - * Starts tracking for a specifc activity - */ - public static pushActivity(name: string, spanContext?: SpanContext): number { - if (!TransactionActivity._isEnabled()) { - // Tracing is not enabled - return 0; - } - - // We want to clear the timeout also here since we push a new activity - clearTimeout(TransactionActivity._debounce); - - const _getCurrentHub = TransactionActivity._getCurrentHub; - if (spanContext && _getCurrentHub) { - const hub = _getCurrentHub(); - if (hub) { - TransactionActivity._activities[TransactionActivity._currentIndex] = { - name, - span: hub.startSpan(spanContext), - }; - } - } else { - TransactionActivity._activities[TransactionActivity._currentIndex] = { - name, - }; - } - - return TransactionActivity._currentIndex++; - } - - /** - * Removes activity and finishes the span in case there is one - */ - public static popActivity(id: number, spanData?: { [key: string]: any }): void { - if (!TransactionActivity._isEnabled()) { - // Tracing is not enabled - return; - } - - const activity = TransactionActivity._activities[id]; - if (activity) { - const span = activity.span; - if (span) { - if (spanData) { - Object.keys(spanData).forEach((key: string) => { - span.setData(key, spanData[key]); - }); - } - span.finish(); - } - // tslint:disable-next-line: no-dynamic-delete - delete TransactionActivity._activities[id]; - } - - const count = Object.keys(TransactionActivity._activities).length; - clearTimeout(TransactionActivity._debounce); - - if (count === 0) { - const timeout = TransactionActivity.options && TransactionActivity.options.idleTimeout; - TransactionActivity._debounce = (setTimeout(() => { - TransactionActivity.finishIdleTransaction(); - }, timeout) as any) as number; - } - } -} - -/** - * Creates breadcrumbs from XHR API calls - */ -function xhrCallback(handlerData: { [key: string]: any }): void { - // tslint:disable: no-unsafe-any - if (handlerData.requestComplete && handlerData.xhr.__sentry_xhr_activity_id__) { - TransactionActivity.popActivity(handlerData.xhr.__sentry_xhr_activity_id__, handlerData.xhr.__sentry_xhr__); - return; - } - // We only capture complete, non-sentry requests - if (handlerData.xhr.__sentry_own_request__) { - return; - } - - const xhr = handlerData.xhr.__sentry_xhr__; - handlerData.xhr.__sentry_xhr_activity_id__ = TransactionActivity.pushActivity('xhr', { - data: { - request_data: xhr.data, - }, - description: `${xhr.method} ${xhr.url}`, - op: 'http', - }); - // tslint:enable: no-unsafe-any -} - -/** - * Creates breadcrumbs from fetch API calls - */ -// function fetchHandler(handlerData: { [key: string]: any }): void { -// // We only capture complete fetch requests -// if (!handlerData.requestComplete) { -// return; -// } - -// const client = getCurrentHub().getClient(); -// const dsn = client && client.getDsn(); - -// if (dsn) { -// const filterUrl = new API(dsn).getStoreEndpoint(); -// // if Sentry key appears in URL, don't capture it as a request -// // but rather as our own 'sentry' type breadcrumb -// if ( -// filterUrl && -// handlerData.fetchData.url.indexOf(filterUrl) !== -1 && -// handlerData.fetchData.method === 'POST' && -// handlerData.args[1] && -// handlerData.args[1].body -// ) { -// addSentryBreadcrumb(handlerData.args[1].body); -// return; -// } -// } - -// if (handlerData.error) { -// getCurrentHub().addBreadcrumb( -// { -// category: 'fetch', -// data: handlerData.fetchData, -// level: Severity.Error, -// type: 'http', -// }, -// { -// data: handlerData.error, -// input: handlerData.args, -// }, -// ); -// } else { -// getCurrentHub().addBreadcrumb( -// { -// category: 'fetch', -// data: handlerData.fetchData, -// type: 'http', -// }, -// { -// input: handlerData.args, -// response: handlerData.response, -// }, -// ); -// } -// } - -/** - * Creates transaction from navigation changes - */ -function historyCallback(_: { [key: string]: any }): void { - if (TransactionActivity.options.startTransactionOnLocationChange) { - TransactionActivity.startIdleTransaction(global.location.href, { - op: 'navigation', - sampled: true, - }); - } -} - -const historyHandler = { - callback: historyCallback, - type: 'history', -}; - -const xhrHandler = { - callback: xhrCallback, - type: 'xhr', -}; - -// tslint:disable-next-line: variable-name -export const TransactionActivityHandlers = [historyHandler, xhrHandler]; diff --git a/packages/apm/test/transactionactivity.test.ts b/packages/apm/test/tracing.test.ts similarity index 69% rename from packages/apm/test/transactionactivity.test.ts rename to packages/apm/test/tracing.test.ts index a480a8347714..c8669b37584e 100644 --- a/packages/apm/test/transactionactivity.test.ts +++ b/packages/apm/test/tracing.test.ts @@ -1,6 +1,6 @@ -import { TransactionActivity } from '../src/integrations/transactionactivity'; +import { Tracing } from '../src/integrations/tracing'; -const transactionActivity: TransactionActivity = new TransactionActivity(); +const tracing: Tracing = new Tracing(); const configureScope = jest.fn(); const startSpan = jest.fn(); @@ -10,14 +10,14 @@ const getCurrentHubMock: any = () => ({ startSpan, }); -transactionActivity.setupOnce(jest.fn(), getCurrentHubMock); +tracing.setupOnce(jest.fn(), getCurrentHubMock); describe('TransactionActivity', () => { afterEach(() => { jest.resetAllMocks(); - (TransactionActivity as any)._activities = {}; - (TransactionActivity as any)._currentIndex = 0; - (TransactionActivity as any)._activeTransaction = undefined; + (Tracing as any)._activities = {}; + (Tracing as any)._currentIndex = 0; + (Tracing as any)._activeTransaction = undefined; }); // test('startSpan with transaction', () => { @@ -38,11 +38,11 @@ describe('TransactionActivity', () => { // }); test('multiple activities ', () => { - TransactionActivity.pushActivity('xhr'); - const a = TransactionActivity.pushActivity('xhr2'); - TransactionActivity.popActivity(a); - TransactionActivity.pushActivity('xhr3'); - expect(Object.keys((TransactionActivity as any)._activities)).toHaveLength(2); + Tracing.pushActivity('xhr'); + const a = Tracing.pushActivity('xhr2'); + Tracing.popActivity(a); + Tracing.pushActivity('xhr3'); + expect(Object.keys((Tracing as any)._activities)).toHaveLength(2); }); // test('finishing a transaction after debounce', () => { From b41142caa632c868629b37d3854ae6e8634f2c8e Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Thu, 21 Nov 2019 15:49:46 +0100 Subject: [PATCH 56/63] feat: Add shouldCreateSpanForRequest option --- packages/apm/src/integrations/tracing.ts | 32 +++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/packages/apm/src/integrations/tracing.ts b/packages/apm/src/integrations/tracing.ts index ebf7db362c03..afe93e93f8a6 100644 --- a/packages/apm/src/integrations/tracing.ts +++ b/packages/apm/src/integrations/tracing.ts @@ -6,6 +6,13 @@ interface TracingOptions { tracingOrigins: Array; traceFetch: boolean; traceXHR: boolean; + /** + * This function will be called before creating a span for a request with the given url. + * Return false if you don't want a span for the given url. + * + * By default it uses the `tracingOrigins` options as a url match. + */ + shouldCreateSpanForRequest(url: string): boolean; idleTimeout: number; startTransactionOnLocationChange: boolean; tracesSampleRate: number; @@ -70,6 +77,10 @@ export class Tracing implements Integration { const defaultTracingOrigins = ['localhost', /^\//]; const defaults = { idleTimeout: 500, + shouldCreateSpanForRequest(url: string): boolean { + const origins = (_options && _options.tracingOrigins) || defaultTracingOrigins; + return origins.some((origin: string | RegExp) => isMatchingPattern(url, origin)); + }, startTransactionOnLocationChange: true, traceFetch: true, traceXHR: true, @@ -393,17 +404,32 @@ export class Tracing implements Integration { * Creates breadcrumbs from XHR API calls */ function xhrCallback(handlerData: { [key: string]: any }): void { + if (!Tracing.options.traceXHR) { + return; + } + + // tslint:disable-next-line: no-unsafe-any + if (!handlerData || !handlerData.xhr || !handlerData.xhr.__sentry_xhr__) { + return; + } + // tslint:disable: no-unsafe-any - if (handlerData.requestComplete && handlerData.xhr.__sentry_xhr_activity_id__) { - Tracing.popActivity(handlerData.xhr.__sentry_xhr_activity_id__, handlerData.xhr.__sentry_xhr__); + const xhr = handlerData.xhr.__sentry_xhr__; + + if (!Tracing.options.shouldCreateSpanForRequest(xhr.url)) { return; } + // We only capture complete, non-sentry requests if (handlerData.xhr.__sentry_own_request__) { return; } - const xhr = handlerData.xhr.__sentry_xhr__; + if (handlerData.requestComplete && handlerData.xhr.__sentry_xhr_activity_id__) { + Tracing.popActivity(handlerData.xhr.__sentry_xhr_activity_id__, handlerData.xhr.__sentry_xhr__); + return; + } + handlerData.xhr.__sentry_xhr_activity_id__ = Tracing.pushActivity('xhr', { data: { request_data: xhr.data, From b34bcf823d4b5bafaa45ea92cd82a628a0480fef Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Thu, 21 Nov 2019 16:58:25 +0100 Subject: [PATCH 57/63] feat: Add fetch tracking --- packages/apm/src/integrations/tracing.ts | 86 +++++++++--------------- 1 file changed, 32 insertions(+), 54 deletions(-) diff --git a/packages/apm/src/integrations/tracing.ts b/packages/apm/src/integrations/tracing.ts index afe93e93f8a6..d6fc2eb352b6 100644 --- a/packages/apm/src/integrations/tracing.ts +++ b/packages/apm/src/integrations/tracing.ts @@ -432,7 +432,8 @@ function xhrCallback(handlerData: { [key: string]: any }): void { handlerData.xhr.__sentry_xhr_activity_id__ = Tracing.pushActivity('xhr', { data: { - request_data: xhr.data, + ...xhr.data, + type: 'xhr', }, description: `${xhr.method} ${xhr.url}`, op: 'http', @@ -443,58 +444,30 @@ function xhrCallback(handlerData: { [key: string]: any }): void { /** * Creates breadcrumbs from fetch API calls */ -// function fetchHandler(handlerData: { [key: string]: any }): void { -// // We only capture complete fetch requests -// if (!handlerData.requestComplete) { -// return; -// } - -// const client = getCurrentHub().getClient(); -// const dsn = client && client.getDsn(); - -// if (dsn) { -// const filterUrl = new API(dsn).getStoreEndpoint(); -// // if Sentry key appears in URL, don't capture it as a request -// // but rather as our own 'sentry' type breadcrumb -// if ( -// filterUrl && -// handlerData.fetchData.url.indexOf(filterUrl) !== -1 && -// handlerData.fetchData.method === 'POST' && -// handlerData.args[1] && -// handlerData.args[1].body -// ) { -// addSentryBreadcrumb(handlerData.args[1].body); -// return; -// } -// } - -// if (handlerData.error) { -// getCurrentHub().addBreadcrumb( -// { -// category: 'fetch', -// data: handlerData.fetchData, -// level: Severity.Error, -// type: 'http', -// }, -// { -// data: handlerData.error, -// input: handlerData.args, -// }, -// ); -// } else { -// getCurrentHub().addBreadcrumb( -// { -// category: 'fetch', -// data: handlerData.fetchData, -// type: 'http', -// }, -// { -// input: handlerData.args, -// response: handlerData.response, -// }, -// ); -// } -// } +function fetchCallback(handlerData: { [key: string]: any }): void { + // tslint:disable: no-unsafe-any + if (!Tracing.options.traceFetch) { + return; + } + + if (handlerData.requestComplete && handlerData.__activity) { + Tracing.popActivity(handlerData.__activity, handlerData.fetchData); + } else { + handlerData.__activity = Tracing.pushActivity('fetch', { + data: { + ...handlerData.fetchData, + type: 'fetch', + }, + description: `${handlerData.fetchData.method} ${handlerData.fetchData.url}`, + op: 'http', + }); + } + + // if (handlerData.error) { + // } else { + // } + // tslint:enable: no-unsafe-any +} /** * Creates transaction from navigation changes @@ -518,5 +491,10 @@ const xhrHandler = { type: 'xhr', }; +const fetchHandler = { + callback: fetchCallback, + type: 'fetch', +}; + // tslint:disable-next-line: variable-name -export const TracingHandlers = [historyHandler, xhrHandler]; +export const TracingHandlers = [historyHandler, xhrHandler, fetchHandler]; From ee0b17bc9e774f8b0c0f785b4f2c346ca9d2dbd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Tue, 26 Nov 2019 14:46:02 +0100 Subject: [PATCH 58/63] ref: Use correct SpanStatus types according to spec --- package-lock.json | 12805 +++++++++++++++++++++++ packages/apm/src/hubextensions.ts | 2 +- packages/apm/src/span.ts | 17 +- packages/apm/test/span.test.ts | 28 +- packages/apm/test/tslint.json | 6 + packages/hub/src/hub.ts | 4 +- packages/node/package.json | 3 +- packages/node/src/handlers.ts | 6 +- packages/node/src/integrations/http.ts | 9 +- packages/node/src/version.ts | 4 +- packages/types/src/index.ts | 2 +- packages/types/src/span.ts | 106 +- packages/utils/src/misc.ts | 102 +- yarn.lock | 253 +- 14 files changed, 13174 insertions(+), 173 deletions(-) create mode 100644 package-lock.json create mode 100644 packages/apm/test/tslint.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000000..180e5bb10736 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,12805 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/core": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.4.tgz", + "integrity": "sha512-+bYbx56j4nYBmpsWtnPUsKW3NdnYxbqyfrP2w9wILBuHzdfIKz9prieZK0DFPyIzkjYVUe4QkusGL07r5pXznQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.4", + "@babel/helpers": "^7.7.4", + "@babel/parser": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.4.tgz", + "integrity": "sha512-m5qo2WgdOJeyYngKImbkyQrnUN1mPceaG5BV+G0E3gWsa4l/jCSryWJdM2x8OuGAOyh+3d5pVYfZWCiNFtynxg==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-function-name": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, + "@babel/helper-split-export-declaration": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helpers": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.7.4.tgz", + "integrity": "sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg==", + "dev": true, + "requires": { + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz", + "integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g==", + "dev": true + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz", + "integrity": "sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/polyfill": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.2.5.tgz", + "integrity": "sha512-8Y/t3MWThtMLYr0YNC/Q76tqN1w30+b0uQMeFUYauG2UGTR19zyUtFrAzT23zNtBxPp+LbE5E/nwV/q/r3y6ug==", + "dev": true, + "requires": { + "core-js": "^2.5.7", + "regenerator-runtime": "^0.12.0" + } + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/traverse": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz", + "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.4", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "@cnakazawa/watch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", + "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", + "dev": true, + "requires": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + } + }, + "@google-cloud/common": { + "version": "0.32.1", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-0.32.1.tgz", + "integrity": "sha512-bLdPzFvvBMtVkwsoBtygE9oUm3yrNmPa71gvOgucYI/GqvNP2tb6RYsDHPq98kvignhcgHGDI5wyNgxaCo8bKQ==", + "dev": true, + "requires": { + "@google-cloud/projectify": "^0.3.3", + "@google-cloud/promisify": "^0.4.0", + "@types/request": "^2.48.1", + "arrify": "^2.0.0", + "duplexify": "^3.6.0", + "ent": "^2.2.0", + "extend": "^3.0.2", + "google-auth-library": "^3.1.1", + "pify": "^4.0.1", + "retry-request": "^4.0.0", + "teeny-request": "^3.11.3" + }, + "dependencies": { + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "@google-cloud/paginator": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-0.2.0.tgz", + "integrity": "sha512-2ZSARojHDhkLvQ+CS32K+iUhBsWg3AEw+uxtqblA7xoCABDyhpj99FPp35xy6A+XlzMhOSrHHaxFE+t6ZTQq0w==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "extend": "^3.0.1", + "split-array-stream": "^2.0.0", + "stream-events": "^1.0.4" + } + }, + "@google-cloud/projectify": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-0.3.3.tgz", + "integrity": "sha512-7522YHQ4IhaafgSunsFF15nG0TGVmxgXidy9cITMe+256RgqfcrfWphiMufW+Ou4kqagW/u3yxwbzVEW3dk2Uw==", + "dev": true + }, + "@google-cloud/promisify": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-0.4.0.tgz", + "integrity": "sha512-4yAHDC52TEMCNcMzVC8WlqnKKKq+Ssi2lXoUg9zWWkZ6U6tq9ZBRYLHHCRdfU+EU9YJsVmivwGcKYCjRGjnf4Q==", + "dev": true + }, + "@google-cloud/storage": { + "version": "2.5.0", + "dev": true, + "requires": { + "@google-cloud/common": "^0.32.0", + "@google-cloud/paginator": "^0.2.0", + "@google-cloud/promisify": "^0.4.0", + "arrify": "^1.0.0", + "async": "^2.0.1", + "compressible": "^2.0.12", + "concat-stream": "^2.0.0", + "date-and-time": "^0.6.3", + "duplexify": "^3.5.0", + "extend": "^3.0.0", + "gcs-resumable-upload": "^1.0.0", + "hash-stream-validation": "^0.2.1", + "mime": "^2.2.0", + "mime-types": "^2.0.8", + "onetime": "^5.1.0", + "pumpify": "^1.5.1", + "snakeize": "^0.1.0", + "stream-events": "^1.0.1", + "teeny-request": "^3.11.3", + "through2": "^3.0.0", + "xdg-basedir": "^3.0.0" + }, + "dependencies": { + "async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "dev": true, + "requires": { + "lodash": "^4.17.10" + } + }, + "concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + } + } + }, + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "@jest/console": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", + "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", + "dev": true, + "requires": { + "@jest/source-map": "^24.9.0", + "chalk": "^2.0.1", + "slash": "^2.0.0" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } + } + }, + "@jest/core": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", + "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", + "dev": true, + "requires": { + "@jest/console": "^24.7.1", + "@jest/reporters": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-changed-files": "^24.9.0", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-resolve-dependencies": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "jest-watcher": "^24.9.0", + "micromatch": "^3.1.10", + "p-each-series": "^1.0.0", + "realpath-native": "^1.1.0", + "rimraf": "^2.5.4", + "slash": "^2.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "@jest/environment": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", + "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", + "dev": true, + "requires": { + "@jest/fake-timers": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0" + } + }, + "@jest/fake-timers": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", + "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0" + } + }, + "@jest/reporters": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", + "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-lib-coverage": "^2.0.2", + "istanbul-lib-instrument": "^3.0.1", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.1", + "istanbul-reports": "^2.2.6", + "jest-haste-map": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "node-notifier": "^5.4.2", + "slash": "^2.0.0", + "source-map": "^0.6.0", + "string-length": "^2.0.0" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } + } + }, + "@jest/source-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", + "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.1.15", + "source-map": "^0.6.0" + } + }, + "@jest/test-result": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", + "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", + "dev": true, + "requires": { + "@jest/console": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/istanbul-lib-coverage": "^2.0.0" + } + }, + "@jest/test-sequencer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", + "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", + "dev": true, + "requires": { + "@jest/test-result": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0" + } + }, + "@jest/transform": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", + "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.9.0", + "babel-plugin-istanbul": "^5.1.0", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.1.15", + "jest-haste-map": "^24.9.0", + "jest-regex-util": "^24.9.0", + "jest-util": "^24.9.0", + "micromatch": "^3.1.10", + "pirates": "^4.0.1", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "2.4.1" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "write-file-atomic": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + } + } + }, + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@lerna/add": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/add/-/add-3.13.3.tgz", + "integrity": "sha512-T3/Lsbo9ZFq+vL3ssaHxA8oKikZAPTJTGFe4CRuQgWCDd/M61+51jeWsngdaHpwzSSRDRjxg8fJTG10y10pnfA==", + "dev": true, + "requires": { + "@lerna/bootstrap": "3.13.3", + "@lerna/command": "3.13.3", + "@lerna/filter-options": "3.13.3", + "@lerna/npm-conf": "3.13.0", + "@lerna/validation-error": "3.13.0", + "dedent": "^0.7.0", + "npm-package-arg": "^6.1.0", + "p-map": "^1.2.0", + "pacote": "^9.5.0", + "semver": "^5.5.0" + } + }, + "@lerna/batch-packages": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/batch-packages/-/batch-packages-3.13.0.tgz", + "integrity": "sha512-TgLBTZ7ZlqilGnzJ3xh1KdAHcySfHytgNRTdG9YomfriTU6kVfp1HrXxKJYVGs7ClPUNt2CTFEOkw0tMBronjw==", + "dev": true, + "requires": { + "@lerna/package-graph": "3.13.0", + "@lerna/validation-error": "3.13.0", + "npmlog": "^4.1.2" + } + }, + "@lerna/bootstrap": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/bootstrap/-/bootstrap-3.13.3.tgz", + "integrity": "sha512-2XzijnLHRZOVQh8pwS7+5GR3cG4uh+EiLrWOishCq2TVzkqgjaS3GGBoef7KMCXfWHoLqAZRr/jEdLqfETLVqg==", + "dev": true, + "requires": { + "@lerna/batch-packages": "3.13.0", + "@lerna/command": "3.13.3", + "@lerna/filter-options": "3.13.3", + "@lerna/has-npm-version": "3.13.3", + "@lerna/npm-install": "3.13.3", + "@lerna/package-graph": "3.13.0", + "@lerna/pulse-till-done": "3.13.0", + "@lerna/rimraf-dir": "3.13.3", + "@lerna/run-lifecycle": "3.13.0", + "@lerna/run-parallel-batches": "3.13.0", + "@lerna/symlink-binary": "3.13.0", + "@lerna/symlink-dependencies": "3.13.0", + "@lerna/validation-error": "3.13.0", + "dedent": "^0.7.0", + "get-port": "^3.2.0", + "multimatch": "^2.1.0", + "npm-package-arg": "^6.1.0", + "npmlog": "^4.1.2", + "p-finally": "^1.0.0", + "p-map": "^1.2.0", + "p-map-series": "^1.0.0", + "p-waterfall": "^1.0.0", + "read-package-tree": "^5.1.6", + "semver": "^5.5.0" + } + }, + "@lerna/changed": { + "version": "3.13.4", + "resolved": "https://registry.npmjs.org/@lerna/changed/-/changed-3.13.4.tgz", + "integrity": "sha512-9lfOyRVObasw6L/z7yCSfsEl1QKy0Eamb8t2Krg1deIoAt+cE3JXOdGGC1MhOSli+7f/U9LyLXjJzIOs/pc9fw==", + "dev": true, + "requires": { + "@lerna/collect-updates": "3.13.3", + "@lerna/command": "3.13.3", + "@lerna/listable": "3.13.0", + "@lerna/output": "3.13.0", + "@lerna/version": "3.13.4" + } + }, + "@lerna/check-working-tree": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/check-working-tree/-/check-working-tree-3.13.3.tgz", + "integrity": "sha512-LoGZvTkne+V1WpVdCTU0XNzFKsQa2AiAFKksGRT0v8NQj6VAPp0jfVYDayTqwaWt2Ne0OGKOFE79Y5LStOuhaQ==", + "dev": true, + "requires": { + "@lerna/describe-ref": "3.13.3", + "@lerna/validation-error": "3.13.0" + } + }, + "@lerna/child-process": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/child-process/-/child-process-3.13.3.tgz", + "integrity": "sha512-3/e2uCLnbU+bydDnDwyadpOmuzazS01EcnOleAnuj9235CU2U97DH6OyoG1EW/fU59x11J+HjIqovh5vBaMQjQ==", + "dev": true, + "requires": { + "chalk": "^2.3.1", + "execa": "^1.0.0", + "strong-log-transformer": "^2.0.0" + } + }, + "@lerna/clean": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/clean/-/clean-3.13.3.tgz", + "integrity": "sha512-xmNauF1PpmDaKdtA2yuRc23Tru4q7UMO6yB1a/TTwxYPYYsAWG/CBK65bV26J7x4RlZtEv06ztYGMa9zh34UXA==", + "dev": true, + "requires": { + "@lerna/command": "3.13.3", + "@lerna/filter-options": "3.13.3", + "@lerna/prompt": "3.13.0", + "@lerna/pulse-till-done": "3.13.0", + "@lerna/rimraf-dir": "3.13.3", + "p-map": "^1.2.0", + "p-map-series": "^1.0.0", + "p-waterfall": "^1.0.0" + } + }, + "@lerna/cli": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/cli/-/cli-3.13.0.tgz", + "integrity": "sha512-HgFGlyCZbYaYrjOr3w/EsY18PdvtsTmDfpUQe8HwDjXlPeCCUgliZjXLOVBxSjiOvPeOSwvopwIHKWQmYbwywg==", + "dev": true, + "requires": { + "@lerna/global-options": "3.13.0", + "dedent": "^0.7.0", + "npmlog": "^4.1.2", + "yargs": "^12.0.1" + } + }, + "@lerna/collect-updates": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/collect-updates/-/collect-updates-3.13.3.tgz", + "integrity": "sha512-sTpALOAxli/ZS+Mjq6fbmjU9YXqFJ2E4FrE1Ijl4wPC5stXEosg2u0Z1uPY+zVKdM+mOIhLxPVdx83rUgRS+Cg==", + "dev": true, + "requires": { + "@lerna/child-process": "3.13.3", + "@lerna/describe-ref": "3.13.3", + "minimatch": "^3.0.4", + "npmlog": "^4.1.2", + "slash": "^1.0.0" + } + }, + "@lerna/command": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/command/-/command-3.13.3.tgz", + "integrity": "sha512-WHFIQCubJV0T8gSLRNr6exZUxTswrh+iAtJCb86SE0Sa+auMPklE8af7w2Yck5GJfewmxSjke3yrjNxQrstx7w==", + "dev": true, + "requires": { + "@lerna/child-process": "3.13.3", + "@lerna/package-graph": "3.13.0", + "@lerna/project": "3.13.1", + "@lerna/validation-error": "3.13.0", + "@lerna/write-log-file": "3.13.0", + "dedent": "^0.7.0", + "execa": "^1.0.0", + "is-ci": "^1.0.10", + "lodash": "^4.17.5", + "npmlog": "^4.1.2" + }, + "dependencies": { + "ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "dev": true + }, + "is-ci": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", + "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "dev": true, + "requires": { + "ci-info": "^1.5.0" + } + } + } + }, + "@lerna/conventional-commits": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/conventional-commits/-/conventional-commits-3.13.0.tgz", + "integrity": "sha512-BeAgcNXuocmLhPxnmKU2Vy8YkPd/Uo+vu2i/p3JGsUldzrPC8iF3IDxH7fuXpEFN2Nfogu7KHachd4tchtOppA==", + "dev": true, + "requires": { + "@lerna/validation-error": "3.13.0", + "conventional-changelog-angular": "^5.0.3", + "conventional-changelog-core": "^3.1.6", + "conventional-recommended-bump": "^4.0.4", + "fs-extra": "^7.0.0", + "get-stream": "^4.0.0", + "npm-package-arg": "^6.1.0", + "npmlog": "^4.1.2", + "pify": "^3.0.0", + "semver": "^5.5.0" + } + }, + "@lerna/create": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/create/-/create-3.13.3.tgz", + "integrity": "sha512-4M5xT1AyUMwt1gCDph4BfW3e6fZmt0KjTa3FoXkUotf/w/eqTsc2IQ+ULz2+gOFQmtuNbqIZEOK3J4P9ArJJ/A==", + "dev": true, + "requires": { + "@lerna/child-process": "3.13.3", + "@lerna/command": "3.13.3", + "@lerna/npm-conf": "3.13.0", + "@lerna/validation-error": "3.13.0", + "camelcase": "^5.0.0", + "dedent": "^0.7.0", + "fs-extra": "^7.0.0", + "globby": "^8.0.1", + "init-package-json": "^1.10.3", + "npm-package-arg": "^6.1.0", + "p-reduce": "^1.0.0", + "pacote": "^9.5.0", + "pify": "^3.0.0", + "semver": "^5.5.0", + "slash": "^1.0.0", + "validate-npm-package-license": "^3.0.3", + "validate-npm-package-name": "^3.0.0", + "whatwg-url": "^7.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } + } + }, + "@lerna/create-symlink": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/create-symlink/-/create-symlink-3.13.0.tgz", + "integrity": "sha512-PTvg3jAAJSAtLFoZDsuTMv1wTOC3XYIdtg54k7uxIHsP8Ztpt+vlilY/Cni0THAqEMHvfiToel76Xdta4TU21Q==", + "dev": true, + "requires": { + "cmd-shim": "^2.0.2", + "fs-extra": "^7.0.0", + "npmlog": "^4.1.2" + } + }, + "@lerna/describe-ref": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/describe-ref/-/describe-ref-3.13.3.tgz", + "integrity": "sha512-5KcLTvjdS4gU5evW8ESbZ0BF44NM5HrP3dQNtWnOUSKJRgsES8Gj0lq9AlB2+YglZfjEftFT03uOYOxnKto4Uw==", + "dev": true, + "requires": { + "@lerna/child-process": "3.13.3", + "npmlog": "^4.1.2" + } + }, + "@lerna/diff": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/diff/-/diff-3.13.3.tgz", + "integrity": "sha512-/DRS2keYbnKaAC+5AkDyZRGkP/kT7v1GlUS0JGZeiRDPQ1H6PzhX09EgE5X6nj0Ytrm0sUasDeN++CDVvgaI+A==", + "dev": true, + "requires": { + "@lerna/child-process": "3.13.3", + "@lerna/command": "3.13.3", + "@lerna/validation-error": "3.13.0", + "npmlog": "^4.1.2" + } + }, + "@lerna/exec": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/exec/-/exec-3.13.3.tgz", + "integrity": "sha512-c0bD4XqM96CTPV8+lvkxzE7mkxiFyv/WNM4H01YvvbFAJzk+S4Y7cBtRkIYFTfkFZW3FLo8pEgtG1ONtIdM+tg==", + "dev": true, + "requires": { + "@lerna/batch-packages": "3.13.0", + "@lerna/child-process": "3.13.3", + "@lerna/command": "3.13.3", + "@lerna/filter-options": "3.13.3", + "@lerna/run-parallel-batches": "3.13.0", + "@lerna/validation-error": "3.13.0" + } + }, + "@lerna/filter-options": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/filter-options/-/filter-options-3.13.3.tgz", + "integrity": "sha512-DbtQX4eRgrBz1wCFWRP99JBD7ODykYme9ykEK79+RrKph40znhJQRlLg4idogj6IsUEzwo1OHjihCzSfnVo6Cg==", + "dev": true, + "requires": { + "@lerna/collect-updates": "3.13.3", + "@lerna/filter-packages": "3.13.0", + "dedent": "^0.7.0" + } + }, + "@lerna/filter-packages": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/filter-packages/-/filter-packages-3.13.0.tgz", + "integrity": "sha512-RWiZWyGy3Mp7GRVBn//CacSnE3Kw82PxE4+H6bQ3pDUw/9atXn7NRX+gkBVQIYeKamh7HyumJtyOKq3Pp9BADQ==", + "dev": true, + "requires": { + "@lerna/validation-error": "3.13.0", + "multimatch": "^2.1.0", + "npmlog": "^4.1.2" + } + }, + "@lerna/get-npm-exec-opts": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-3.13.0.tgz", + "integrity": "sha512-Y0xWL0rg3boVyJk6An/vurKzubyJKtrxYv2sj4bB8Mc5zZ3tqtv0ccbOkmkXKqbzvNNF7VeUt1OJ3DRgtC/QZw==", + "dev": true, + "requires": { + "npmlog": "^4.1.2" + } + }, + "@lerna/get-packed": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/get-packed/-/get-packed-3.13.0.tgz", + "integrity": "sha512-EgSim24sjIjqQDC57bgXD9l22/HCS93uQBbGpkzEOzxAVzEgpZVm7Fm1t8BVlRcT2P2zwGnRadIvxTbpQuDPTg==", + "dev": true, + "requires": { + "fs-extra": "^7.0.0", + "ssri": "^6.0.1", + "tar": "^4.4.8" + } + }, + "@lerna/github-client": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/github-client/-/github-client-3.13.3.tgz", + "integrity": "sha512-fcJkjab4kX0zcLLSa/DCUNvU3v8wmy2c1lhdIbL7s7gABmDcV0QZq93LhnEee3VkC9UpnJ6GKG4EkD7eIifBnA==", + "dev": true, + "requires": { + "@lerna/child-process": "3.13.3", + "@octokit/plugin-enterprise-rest": "^2.1.1", + "@octokit/rest": "^16.16.0", + "git-url-parse": "^11.1.2", + "npmlog": "^4.1.2" + }, + "dependencies": { + "@octokit/endpoint": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.5.1.tgz", + "integrity": "sha512-nBFhRUb5YzVTCX/iAK1MgQ4uWo89Gu0TH00qQHoYRCsE12dWcG1OiLd7v2EIo2+tpUKPMOQ62QFy9hy9Vg2ULg==", + "dev": true, + "requires": { + "@octokit/types": "^2.0.0", + "is-plain-object": "^3.0.0", + "universal-user-agent": "^4.0.0" + } + }, + "@octokit/request": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.3.1.tgz", + "integrity": "sha512-5/X0AL1ZgoU32fAepTfEoggFinO3rxsMLtzhlUX+RctLrusn/CApJuGFCd0v7GMFhF+8UiCsTTfsu7Fh1HnEJg==", + "dev": true, + "requires": { + "@octokit/endpoint": "^5.5.0", + "@octokit/request-error": "^1.0.1", + "@octokit/types": "^2.0.0", + "deprecation": "^2.0.0", + "is-plain-object": "^3.0.0", + "node-fetch": "^2.3.0", + "once": "^1.4.0", + "universal-user-agent": "^4.0.0" + } + }, + "@octokit/rest": { + "version": "16.35.0", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.35.0.tgz", + "integrity": "sha512-9ShFqYWo0CLoGYhA1FdtdykJuMzS/9H6vSbbQWDX4pWr4p9v+15MsH/wpd/3fIU+tSxylaNO48+PIHqOkBRx3w==", + "dev": true, + "requires": { + "@octokit/request": "^5.2.0", + "@octokit/request-error": "^1.0.2", + "atob-lite": "^2.0.0", + "before-after-hook": "^2.0.0", + "btoa-lite": "^1.0.0", + "deprecation": "^2.0.0", + "lodash.get": "^4.4.2", + "lodash.set": "^4.3.2", + "lodash.uniq": "^4.5.0", + "octokit-pagination-methods": "^1.1.0", + "once": "^1.4.0", + "universal-user-agent": "^4.0.0" + } + }, + "before-after-hook": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz", + "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==", + "dev": true + }, + "is-plain-object": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz", + "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==", + "dev": true, + "requires": { + "isobject": "^4.0.0" + } + }, + "isobject": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", + "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", + "dev": true + }, + "universal-user-agent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.0.tgz", + "integrity": "sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==", + "dev": true, + "requires": { + "os-name": "^3.1.0" + } + } + } + }, + "@lerna/global-options": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/global-options/-/global-options-3.13.0.tgz", + "integrity": "sha512-SlZvh1gVRRzYLVluz9fryY1nJpZ0FHDGB66U9tFfvnnxmueckRQxLopn3tXj3NU1kc3QANT2I5BsQkOqZ4TEFQ==", + "dev": true + }, + "@lerna/has-npm-version": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/has-npm-version/-/has-npm-version-3.13.3.tgz", + "integrity": "sha512-mQzoghRw4dBg0R9FFfHrj0TH0glvXyzdEZmYZ8Isvx5BSuEEwpsryoywuZSdppcvLu8o7NAdU5Tac8cJ/mT52w==", + "dev": true, + "requires": { + "@lerna/child-process": "3.13.3", + "semver": "^5.5.0" + } + }, + "@lerna/import": { + "version": "3.13.4", + "resolved": "https://registry.npmjs.org/@lerna/import/-/import-3.13.4.tgz", + "integrity": "sha512-dn6eNuPEljWsifBEzJ9B6NoaLwl/Zvof7PBUPA4hRyRlqG5sXRn6F9DnusMTovvSarbicmTURbOokYuotVWQQA==", + "dev": true, + "requires": { + "@lerna/child-process": "3.13.3", + "@lerna/command": "3.13.3", + "@lerna/prompt": "3.13.0", + "@lerna/pulse-till-done": "3.13.0", + "@lerna/validation-error": "3.13.0", + "dedent": "^0.7.0", + "fs-extra": "^7.0.0", + "p-map-series": "^1.0.0" + } + }, + "@lerna/init": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/init/-/init-3.13.3.tgz", + "integrity": "sha512-bK/mp0sF6jT0N+c+xrbMCqN4xRoiZCXQzlYsyACxPK99KH/mpHv7hViZlTYUGlYcymtew6ZC770miv5A9wF9hA==", + "dev": true, + "requires": { + "@lerna/child-process": "3.13.3", + "@lerna/command": "3.13.3", + "fs-extra": "^7.0.0", + "p-map": "^1.2.0", + "write-json-file": "^2.3.0" + } + }, + "@lerna/link": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/link/-/link-3.13.3.tgz", + "integrity": "sha512-IHhtdhA0KlIdevCsq6WHkI2rF3lHWHziJs2mlrEWAKniVrFczbELON1KJAgdJS1k3kAP/WeWVqmIYZ2hJDxMvg==", + "dev": true, + "requires": { + "@lerna/command": "3.13.3", + "@lerna/package-graph": "3.13.0", + "@lerna/symlink-dependencies": "3.13.0", + "p-map": "^1.2.0", + "slash": "^1.0.0" + } + }, + "@lerna/list": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/list/-/list-3.13.3.tgz", + "integrity": "sha512-rLRDsBCkydMq2FL6WY1J/elvnXIjxxRtb72lfKHdvDEqVdquT5Qgt9ci42hwjmcocFwWcFJgF6BZozj5pbc13A==", + "dev": true, + "requires": { + "@lerna/command": "3.13.3", + "@lerna/filter-options": "3.13.3", + "@lerna/listable": "3.13.0", + "@lerna/output": "3.13.0" + } + }, + "@lerna/listable": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/listable/-/listable-3.13.0.tgz", + "integrity": "sha512-liYJ/WBUYP4N4MnSVZuLUgfa/jy3BZ02/1Om7xUY09xGVSuNVNEeB8uZUMSC+nHqFHIsMPZ8QK9HnmZb1E/eTA==", + "dev": true, + "requires": { + "@lerna/batch-packages": "3.13.0", + "chalk": "^2.3.1", + "columnify": "^1.5.4" + } + }, + "@lerna/log-packed": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/log-packed/-/log-packed-3.13.0.tgz", + "integrity": "sha512-Rmjrcz+6aM6AEcEVWmurbo8+AnHOvYtDpoeMMJh9IZ9SmZr2ClXzmD7wSvjTQc8BwOaiWjjC/ukcT0UYA2m7wg==", + "dev": true, + "requires": { + "byte-size": "^4.0.3", + "columnify": "^1.5.4", + "has-unicode": "^2.0.1", + "npmlog": "^4.1.2" + } + }, + "@lerna/npm-conf": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-conf/-/npm-conf-3.13.0.tgz", + "integrity": "sha512-Jg2kANsGnhg+fbPEzE0X9nX5oviEAvWj0nYyOkcE+cgWuT7W0zpnPXC4hA4C5IPQGhwhhh0IxhWNNHtjTuw53g==", + "dev": true, + "requires": { + "config-chain": "^1.1.11", + "pify": "^3.0.0" + } + }, + "@lerna/npm-dist-tag": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-dist-tag/-/npm-dist-tag-3.13.0.tgz", + "integrity": "sha512-mcuhw34JhSRFrbPn0vedbvgBTvveG52bR2lVE3M3tfE8gmR/cKS/EJFO4AUhfRKGCTFn9rjaSEzlFGYV87pemQ==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.1.0", + "npm-registry-fetch": "^3.9.0", + "npmlog": "^4.1.2" + }, + "dependencies": { + "cacache": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz", + "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "make-fetch-happen": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-4.0.2.tgz", + "integrity": "sha512-YMJrAjHSb/BordlsDEcVcPyTbiJKkzqMf48N8dAJZT9Zjctrkb6Yg4TY9Sq2AwSIQJFn5qBBKVTYt3vP5FMIHA==", + "dev": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^11.3.3", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + } + }, + "npm-registry-fetch": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-3.9.1.tgz", + "integrity": "sha512-VQCEZlydXw4AwLROAXWUR7QDfe2Y8Id/vpAgp6TI1/H78a4SiQ1kQrKZALm5/zxM5n4HIi+aYb+idUAV/RuY0Q==", + "dev": true, + "requires": { + "JSONStream": "^1.3.4", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.4.1", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^4.0.2", + "npm-package-arg": "^6.1.0" + } + } + } + }, + "@lerna/npm-install": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/npm-install/-/npm-install-3.13.3.tgz", + "integrity": "sha512-7Jig9MLpwAfcsdQ5UeanAjndChUjiTjTp50zJ+UZz4CbIBIDhoBehvNMTCL2G6pOEC7sGEg6sAqJINAqred6Tg==", + "dev": true, + "requires": { + "@lerna/child-process": "3.13.3", + "@lerna/get-npm-exec-opts": "3.13.0", + "fs-extra": "^7.0.0", + "npm-package-arg": "^6.1.0", + "npmlog": "^4.1.2", + "signal-exit": "^3.0.2", + "write-pkg": "^3.1.0" + } + }, + "@lerna/npm-publish": { + "version": "3.13.2", + "resolved": "https://registry.npmjs.org/@lerna/npm-publish/-/npm-publish-3.13.2.tgz", + "integrity": "sha512-HMucPyEYZfom5tRJL4GsKBRi47yvSS2ynMXYxL3kO0ie+j9J7cb0Ir8NmaAMEd3uJWJVFCPuQarehyfTDZsSxg==", + "dev": true, + "requires": { + "@lerna/run-lifecycle": "3.13.0", + "figgy-pudding": "^3.5.1", + "fs-extra": "^7.0.0", + "libnpmpublish": "^1.1.1", + "npm-package-arg": "^6.1.0", + "npmlog": "^4.1.2", + "pify": "^3.0.0", + "read-package-json": "^2.0.13" + } + }, + "@lerna/npm-run-script": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/npm-run-script/-/npm-run-script-3.13.3.tgz", + "integrity": "sha512-qR4o9BFt5hI8Od5/DqLalOJydnKpiQFEeN0h9xZi7MwzuX1Ukwh3X22vqsX4YRbipIelSFtrDzleNVUm5jj0ow==", + "dev": true, + "requires": { + "@lerna/child-process": "3.13.3", + "@lerna/get-npm-exec-opts": "3.13.0", + "npmlog": "^4.1.2" + } + }, + "@lerna/output": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/output/-/output-3.13.0.tgz", + "integrity": "sha512-7ZnQ9nvUDu/WD+bNsypmPG5MwZBwu86iRoiW6C1WBuXXDxM5cnIAC1m2WxHeFnjyMrYlRXM9PzOQ9VDD+C15Rg==", + "dev": true, + "requires": { + "npmlog": "^4.1.2" + } + }, + "@lerna/pack-directory": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/@lerna/pack-directory/-/pack-directory-3.13.1.tgz", + "integrity": "sha512-kXnyqrkQbCIZOf1054N88+8h0ItC7tUN5v9ca/aWpx298gsURpxUx/1TIKqijL5TOnHMyIkj0YJmnH/PyBVLKA==", + "dev": true, + "requires": { + "@lerna/get-packed": "3.13.0", + "@lerna/package": "3.13.0", + "@lerna/run-lifecycle": "3.13.0", + "figgy-pudding": "^3.5.1", + "npm-packlist": "^1.4.1", + "npmlog": "^4.1.2", + "tar": "^4.4.8", + "temp-write": "^3.4.0" + } + }, + "@lerna/package": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/package/-/package-3.13.0.tgz", + "integrity": "sha512-kSKO0RJQy093BufCQnkhf1jB4kZnBvL7kK5Ewolhk5gwejN+Jofjd8DGRVUDUJfQ0CkW1o6GbUeZvs8w8VIZDg==", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "npm-package-arg": "^6.1.0", + "write-pkg": "^3.1.0" + } + }, + "@lerna/package-graph": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/package-graph/-/package-graph-3.13.0.tgz", + "integrity": "sha512-3mRF1zuqFE1HEFmMMAIggXy+f+9cvHhW/jzaPEVyrPNLKsyfJQtpTNzeI04nfRvbAh+Gd2aNksvaW/w3xGJnnw==", + "dev": true, + "requires": { + "@lerna/validation-error": "3.13.0", + "npm-package-arg": "^6.1.0", + "semver": "^5.5.0" + } + }, + "@lerna/project": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/@lerna/project/-/project-3.13.1.tgz", + "integrity": "sha512-/GoCrpsCCTyb9sizk1+pMBrIYchtb+F1uCOn3cjn9yenyG/MfYEnlfrbV5k/UDud0Ei75YBLbmwCbigHkAKazQ==", + "dev": true, + "requires": { + "@lerna/package": "3.13.0", + "@lerna/validation-error": "3.13.0", + "cosmiconfig": "^5.1.0", + "dedent": "^0.7.0", + "dot-prop": "^4.2.0", + "glob-parent": "^3.1.0", + "globby": "^8.0.1", + "load-json-file": "^4.0.0", + "npmlog": "^4.1.2", + "p-map": "^1.2.0", + "resolve-from": "^4.0.0", + "write-json-file": "^2.3.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "@lerna/prompt": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/prompt/-/prompt-3.13.0.tgz", + "integrity": "sha512-P+lWSFokdyvYpkwC3it9cE0IF2U5yy2mOUbGvvE4iDb9K7TyXGE+7lwtx2thtPvBAfIb7O13POMkv7df03HJeA==", + "dev": true, + "requires": { + "inquirer": "^6.2.0", + "npmlog": "^4.1.2" + } + }, + "@lerna/publish": { + "version": "3.13.4", + "resolved": "https://registry.npmjs.org/@lerna/publish/-/publish-3.13.4.tgz", + "integrity": "sha512-v03pabiPlqCDwX6cVNis1PDdT6/jBgkVb5Nl4e8wcJXevIhZw3ClvtI94gSZu/wdoVFX0RMfc8QBVmaimSO0qg==", + "dev": true, + "requires": { + "@lerna/batch-packages": "3.13.0", + "@lerna/check-working-tree": "3.13.3", + "@lerna/child-process": "3.13.3", + "@lerna/collect-updates": "3.13.3", + "@lerna/command": "3.13.3", + "@lerna/describe-ref": "3.13.3", + "@lerna/log-packed": "3.13.0", + "@lerna/npm-conf": "3.13.0", + "@lerna/npm-dist-tag": "3.13.0", + "@lerna/npm-publish": "3.13.2", + "@lerna/output": "3.13.0", + "@lerna/pack-directory": "3.13.1", + "@lerna/prompt": "3.13.0", + "@lerna/pulse-till-done": "3.13.0", + "@lerna/run-lifecycle": "3.13.0", + "@lerna/run-parallel-batches": "3.13.0", + "@lerna/validation-error": "3.13.0", + "@lerna/version": "3.13.4", + "figgy-pudding": "^3.5.1", + "fs-extra": "^7.0.0", + "libnpmaccess": "^3.0.1", + "npm-package-arg": "^6.1.0", + "npm-registry-fetch": "^3.9.0", + "npmlog": "^4.1.2", + "p-finally": "^1.0.0", + "p-map": "^1.2.0", + "p-pipe": "^1.2.0", + "p-reduce": "^1.0.0", + "pacote": "^9.5.0", + "semver": "^5.5.0" + }, + "dependencies": { + "cacache": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz", + "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "make-fetch-happen": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-4.0.2.tgz", + "integrity": "sha512-YMJrAjHSb/BordlsDEcVcPyTbiJKkzqMf48N8dAJZT9Zjctrkb6Yg4TY9Sq2AwSIQJFn5qBBKVTYt3vP5FMIHA==", + "dev": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^11.3.3", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + } + }, + "npm-registry-fetch": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-3.9.1.tgz", + "integrity": "sha512-VQCEZlydXw4AwLROAXWUR7QDfe2Y8Id/vpAgp6TI1/H78a4SiQ1kQrKZALm5/zxM5n4HIi+aYb+idUAV/RuY0Q==", + "dev": true, + "requires": { + "JSONStream": "^1.3.4", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.4.1", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^4.0.2", + "npm-package-arg": "^6.1.0" + } + } + } + }, + "@lerna/pulse-till-done": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/pulse-till-done/-/pulse-till-done-3.13.0.tgz", + "integrity": "sha512-1SOHpy7ZNTPulzIbargrgaJX387csN7cF1cLOGZiJQA6VqnS5eWs2CIrG8i8wmaUavj2QlQ5oEbRMVVXSsGrzA==", + "dev": true, + "requires": { + "npmlog": "^4.1.2" + } + }, + "@lerna/resolve-symlink": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/resolve-symlink/-/resolve-symlink-3.13.0.tgz", + "integrity": "sha512-Lc0USSFxwDxUs5JvIisS8JegjA6SHSAWJCMvi2osZx6wVRkEDlWG2B1JAfXUzCMNfHoZX0/XX9iYZ+4JIpjAtg==", + "dev": true, + "requires": { + "fs-extra": "^7.0.0", + "npmlog": "^4.1.2", + "read-cmd-shim": "^1.0.1" + } + }, + "@lerna/rimraf-dir": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/rimraf-dir/-/rimraf-dir-3.13.3.tgz", + "integrity": "sha512-d0T1Hxwu3gpYVv73ytSL+/Oy8JitsmvOYUR5ouRSABsmqS7ZZCh5t6FgVDDGVXeuhbw82+vuny1Og6Q0k4ilqw==", + "dev": true, + "requires": { + "@lerna/child-process": "3.13.3", + "npmlog": "^4.1.2", + "path-exists": "^3.0.0", + "rimraf": "^2.6.2" + } + }, + "@lerna/run": { + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/@lerna/run/-/run-3.13.3.tgz", + "integrity": "sha512-ygnLIfIYS6YY1JHWOM4CsdZiY8kTYPsDFOLAwASlRnlAXF9HiMT08GFXLmMHIblZJ8yJhsM2+QgraCB0WdxzOQ==", + "dev": true, + "requires": { + "@lerna/batch-packages": "3.13.0", + "@lerna/command": "3.13.3", + "@lerna/filter-options": "3.13.3", + "@lerna/npm-run-script": "3.13.3", + "@lerna/output": "3.13.0", + "@lerna/run-parallel-batches": "3.13.0", + "@lerna/timer": "3.13.0", + "@lerna/validation-error": "3.13.0", + "p-map": "^1.2.0" + } + }, + "@lerna/run-lifecycle": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/run-lifecycle/-/run-lifecycle-3.13.0.tgz", + "integrity": "sha512-oyiaL1biZdjpmjh6X/5C4w07wNFyiwXSSHH5GQB4Ay4BPwgq9oNhCcxRoi0UVZlZ1YwzSW8sTwLgj8emkIo3Yg==", + "dev": true, + "requires": { + "@lerna/npm-conf": "3.13.0", + "figgy-pudding": "^3.5.1", + "npm-lifecycle": "^2.1.0", + "npmlog": "^4.1.2" + } + }, + "@lerna/run-parallel-batches": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/run-parallel-batches/-/run-parallel-batches-3.13.0.tgz", + "integrity": "sha512-bICFBR+cYVF1FFW+Tlm0EhWDioTUTM6dOiVziDEGE1UZha1dFkMYqzqdSf4bQzfLS31UW/KBd/2z8jy2OIjEjg==", + "dev": true, + "requires": { + "p-map": "^1.2.0", + "p-map-series": "^1.0.0" + } + }, + "@lerna/symlink-binary": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/symlink-binary/-/symlink-binary-3.13.0.tgz", + "integrity": "sha512-obc4Y6jxywkdaCe+DB0uTxYqP0IQ8mFWvN+k/YMbwH4G2h7M7lCBWgPy8e7xw/50+1II9tT2sxgx+jMus1sTJg==", + "dev": true, + "requires": { + "@lerna/create-symlink": "3.13.0", + "@lerna/package": "3.13.0", + "fs-extra": "^7.0.0", + "p-map": "^1.2.0" + } + }, + "@lerna/symlink-dependencies": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/symlink-dependencies/-/symlink-dependencies-3.13.0.tgz", + "integrity": "sha512-7CyN5WYEPkbPLbqHBIQg/YiimBzb5cIGQB0E9IkLs3+racq2vmUNQZn38LOaazQacAA83seB+zWSxlI6H+eXSg==", + "dev": true, + "requires": { + "@lerna/create-symlink": "3.13.0", + "@lerna/resolve-symlink": "3.13.0", + "@lerna/symlink-binary": "3.13.0", + "fs-extra": "^7.0.0", + "p-finally": "^1.0.0", + "p-map": "^1.2.0", + "p-map-series": "^1.0.0" + } + }, + "@lerna/timer": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/timer/-/timer-3.13.0.tgz", + "integrity": "sha512-RHWrDl8U4XNPqY5MQHkToWS9jHPnkLZEt5VD+uunCKTfzlxGnRCr3/zVr8VGy/uENMYpVP3wJa4RKGY6M0vkRw==", + "dev": true + }, + "@lerna/validation-error": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/validation-error/-/validation-error-3.13.0.tgz", + "integrity": "sha512-SiJP75nwB8GhgwLKQfdkSnDufAaCbkZWJqEDlKOUPUvVOplRGnfL+BPQZH5nvq2BYSRXsksXWZ4UHVnQZI/HYA==", + "dev": true, + "requires": { + "npmlog": "^4.1.2" + } + }, + "@lerna/version": { + "version": "3.13.4", + "resolved": "https://registry.npmjs.org/@lerna/version/-/version-3.13.4.tgz", + "integrity": "sha512-pptWUEgN/lUTQZu34+gfH1g4Uhs7TDKRcdZY9A4T9k6RTOwpKC2ceLGiXdeR+ZgQJAey2C4qiE8fo5Z6Rbc6QA==", + "dev": true, + "requires": { + "@lerna/batch-packages": "3.13.0", + "@lerna/check-working-tree": "3.13.3", + "@lerna/child-process": "3.13.3", + "@lerna/collect-updates": "3.13.3", + "@lerna/command": "3.13.3", + "@lerna/conventional-commits": "3.13.0", + "@lerna/github-client": "3.13.3", + "@lerna/output": "3.13.0", + "@lerna/prompt": "3.13.0", + "@lerna/run-lifecycle": "3.13.0", + "@lerna/validation-error": "3.13.0", + "chalk": "^2.3.1", + "dedent": "^0.7.0", + "minimatch": "^3.0.4", + "npmlog": "^4.1.2", + "p-map": "^1.2.0", + "p-pipe": "^1.2.0", + "p-reduce": "^1.0.0", + "p-waterfall": "^1.0.0", + "semver": "^5.5.0", + "slash": "^1.0.0", + "temp-write": "^3.4.0" + } + }, + "@lerna/write-log-file": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@lerna/write-log-file/-/write-log-file-3.13.0.tgz", + "integrity": "sha512-RibeMnDPvlL8bFYW5C8cs4mbI3AHfQef73tnJCQ/SgrXZHehmHnsyWUiE7qDQCAo+B1RfTapvSyFF69iPj326A==", + "dev": true, + "requires": { + "npmlog": "^4.1.2", + "write-file-atomic": "^2.3.0" + } + }, + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dev": true, + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, + "@octokit/endpoint": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-3.2.3.tgz", + "integrity": "sha512-yUPCt4vMIOclox13CUxzuKiPJIFo46b/6GhUnUTw5QySczN1L0DtSxgmIZrZV4SAb9EyAqrceoyrWoYVnfF2AA==", + "dev": true, + "requires": { + "deepmerge": "3.2.0", + "is-plain-object": "^2.0.4", + "universal-user-agent": "^2.0.1", + "url-template": "^2.0.8" + } + }, + "@octokit/plugin-enterprise-rest": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-2.2.2.tgz", + "integrity": "sha512-CTZr64jZYhGWNTDGlSJ2mvIlFsm9OEO3LqWn9I/gmoHI4jRBp4kpHoFYNemG4oA75zUAcmbuWblb7jjP877YZw==", + "dev": true + }, + "@octokit/request": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-2.3.0.tgz", + "integrity": "sha512-5YRqYNZOAaL7+nt7w3Scp6Sz4P2g7wKFP9npx1xdExMomk8/M/ICXVLYVam2wzxeY0cIc6wcKpjC5KI4jiNbGw==", + "dev": true, + "requires": { + "@octokit/endpoint": "^3.1.1", + "is-plain-object": "^2.0.4", + "node-fetch": "^2.3.0", + "universal-user-agent": "^2.0.1" + } + }, + "@octokit/request-error": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.0.tgz", + "integrity": "sha512-DNBhROBYjjV/I9n7A8kVkmQNkqFAMem90dSxqvPq57e2hBr7mNTX98y3R2zDpqMQHVRpBDjsvsfIGgBzy+4PAg==", + "dev": true, + "requires": { + "@octokit/types": "^2.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "@octokit/rest": { + "version": "16.15.0", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.15.0.tgz", + "integrity": "sha512-Un+e7rgh38RtPOTe453pT/KPM/p2KZICimBmuZCd2wEo8PacDa4h6RqTPZs+f2DPazTTqdM7QU4LKlUjgiBwWw==", + "dev": true, + "requires": { + "@octokit/request": "2.3.0", + "before-after-hook": "^1.2.0", + "btoa-lite": "^1.0.0", + "lodash.get": "^4.4.2", + "lodash.set": "^4.3.2", + "lodash.uniq": "^4.5.0", + "octokit-pagination-methods": "^1.1.0", + "universal-user-agent": "^2.0.0", + "url-template": "^2.0.8" + } + }, + "@octokit/types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.0.2.tgz", + "integrity": "sha512-StASIL2lgT3TRjxv17z9pAqbnI7HGu9DrJlg3sEBFfCLaMEqp+O3IQPUF6EZtQ4xkAu2ml6kMBBCtGxjvmtmuQ==", + "dev": true, + "requires": { + "@types/node": ">= 8" + } + }, + "@sinonjs/commons": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.6.0.tgz", + "integrity": "sha512-w4/WHG7C4WWFyE5geCieFJF6MZkbW4VAriol5KlmQXpAQdxvV0p26sqNZOW6Qyw6Y0l9K4g+cHvvczR2sEEpqg==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/formatio": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.1.tgz", + "integrity": "sha512-tsHvOB24rvyvV2+zKMmPkZ7dXX6LSLKZ7aOtXY6Edklp0uRcgGpOsQTTGTcWViFyx4uhWc6GV8QdnALbIbIdeQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^3.1.0" + } + }, + "@sinonjs/samsam": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.1.tgz", + "integrity": "sha512-wRSfmyd81swH0hA1bxJZJ57xr22kC07a1N4zuIL47yTS04bDk6AoCkczcqHEjcRPmJ+FruGJ9WBQiJwMtIElFw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.0.2", + "array-from": "^2.1.1", + "lodash": "^4.17.11" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, + "@strictsoftware/typedoc-plugin-monorepo": { + "version": "0.2.1", + "dev": true, + "requires": { + "highlight.js": "^9.15.6", + "marked": "^0.6.1" + }, + "dependencies": { + "highlight.js": { + "version": "9.15.6", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.6.tgz", + "integrity": "sha512-zozTAWM1D6sozHo8kqhfYgsac+B+q0PmsjXeyDrYIHHcBN0zTVT66+s2GW1GZv7DbyaROdLXKdabwS/WqPyIdQ==", + "dev": true + }, + "marked": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.6.1.tgz", + "integrity": "sha512-+H0L3ibcWhAZE02SKMqmvYsErLo4EAVJxu5h3bHBBDvvjeWXtl92rGUSBYHL2++5Y+RSNgl8dYOAXcYe7lp1fA==", + "dev": true + } + } + }, + "@types/babel__core": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", + "integrity": "sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.0.tgz", + "integrity": "sha512-c1mZUu4up5cp9KROs/QAw0gTeHrw/x7m52LcnvMxxOZ03DmLwPV0MlGmlgzV3cnSdjhJOZsj7E7FHeioai+egw==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", + "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.8.tgz", + "integrity": "sha512-yGeB2dHEdvxjP0y4UbRtQaSkXJ9649fYCmIdRoul5kfAoGCwxuCbMhag0k3RPfnuh9kPGm8x89btcfDEXdVWGw==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/body-parser": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.1.tgz", + "integrity": "sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w==", + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==", + "dev": true + }, + "@types/chai": { + "version": "4.1.7", + "dev": true + }, + "@types/connect": { + "version": "3.4.32", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", + "integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==", + "requires": { + "@types/node": "*" + } + }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "@types/express": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.2.tgz", + "integrity": "sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.0.tgz", + "integrity": "sha512-Xnub7w57uvcBqFdIGoRg1KhNOeEj0vB6ykUM7uFWyxvbdE89GFyqgmUcanAriMr4YOxNFZBAWkfcWIb4WBPt3g==", + "requires": { + "@types/node": "*", + "@types/range-parser": "*" + } + }, + "@types/fs-extra": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.0.5.tgz", + "integrity": "sha512-w7iqhDH9mN8eLClQOYTkhdYUOSpp25eXxfc6VbFOGtzxW34JcvctH2bKjj4jD4++z4R5iO5D+pg48W2e03I65A==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/handlebars": { + "version": "4.0.40", + "resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.0.40.tgz", + "integrity": "sha512-sGWNtsjNrLOdKha2RV1UeF8+UbQnPSG7qbe5wwbni0mw4h2gHXyPFUMOC+xwGirIiiydM/HSqjDO4rk6NFB18w==", + "dev": true + }, + "@types/highlight.js": { + "version": "9.12.3", + "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.3.tgz", + "integrity": "sha512-pGF/zvYOACZ/gLGWdQH8zSwteQS1epp68yRcVLJMgUck/MjEn/FBYmPub9pXT8C1e4a8YZfHo1CKyV8q1vKUnQ==", + "dev": true + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", + "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", + "integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", + "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "24.0.11", + "dev": true, + "requires": { + "@types/jest-diff": "*" + } + }, + "@types/jest-diff": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/jest-diff/-/jest-diff-20.0.1.tgz", + "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", + "dev": true + }, + "@types/lodash": { + "version": "4.14.121", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.121.tgz", + "integrity": "sha512-ORj7IBWj13iYufXt/VXrCNMbUuCTJfhzme5kx9U/UtcIPdJYuvPDUAlHlbNhz/8lKCLy9XGIZnGrqXOtQbPGoQ==", + "dev": true + }, + "@types/marked": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.4.2.tgz", + "integrity": "sha512-cDB930/7MbzaGF6U3IwSQp6XBru8xWajF5PV2YZZeV8DyiliTuld11afVztGI9+yJZ29il5E+NpGA6ooV/Cjkg==", + "dev": true + }, + "@types/mime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz", + "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==" + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/mocha": { + "version": "5.2.6", + "dev": true + }, + "@types/node": { + "version": "11.13.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.7.tgz", + "integrity": "sha512-suFHr6hcA9mp8vFrZTgrmqW2ZU3mbWsryQtQlY/QvwTISCw7nw/j+bCQPPohqmskhmqa5wLNuMHTTsc+xf1MQg==" + }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" + }, + "@types/raven": { + "version": "2.5.3", + "dev": true, + "requires": { + "@types/node": "*" + }, + "dependencies": { + "@types/node": { + "version": "11.9.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.9.4.tgz", + "integrity": "sha512-Zl8dGvAcEmadgs1tmSPcvwzO1YRsz38bVJQvH1RvRqSR9/5n61Q1ktcDL0ht3FXWR+ZpVmXVwN1LuH4Ax23NsA==", + "dev": true + } + } + }, + "@types/request": { + "version": "2.48.3", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.3.tgz", + "integrity": "sha512-3Wo2jNYwqgXcIz/rrq18AdOZUQB8cQ34CXZo+LUwPJNpvRAL86+Kc2wwI8mqpz9Cr1V+enIox5v+WZhy/p3h8w==", + "dev": true, + "requires": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } + }, + "@types/serve-static": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz", + "integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==", + "requires": { + "@types/express-serve-static-core": "*", + "@types/mime": "*" + } + }, + "@types/shelljs": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.3.tgz", + "integrity": "sha512-miY41hqc5SkRlsZDod3heDa4OS9xv8G77EMBQuSpqq86HBn66l7F+f8y9YKm+1PIuwC8QEZVwN8YxOOG7Y67fA==", + "dev": true, + "requires": { + "@types/glob": "*", + "@types/node": "*" + } + }, + "@types/sinon": { + "version": "7.0.11", + "dev": true + }, + "@types/stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", + "dev": true + }, + "@types/tough-cookie": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.5.tgz", + "integrity": "sha512-SCcK7mvGi3+ZNz833RRjFIxrn4gI1PPR3NtuIS+6vMkvmsGjosqTJwRt5bAEFLRz+wtJMWv8+uOnZf2hi2QXTg==", + "dev": true + }, + "@types/yargs": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", + "integrity": "sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", + "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "abab": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", + "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "optional": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-globals": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", + "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", + "dev": true, + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", + "dev": true + } + } + }, + "acorn-walk": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", + "dev": true + }, + "address": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz", + "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==", + "dev": true, + "optional": true + }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "agentkeepalive": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", + "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", + "dev": true, + "requires": { + "humanize-ms": "^1.2.1" + } + }, + "ajv": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz", + "integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true, + "optional": true + }, + "ansi-align": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", + "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "dev": true, + "optional": true, + "requires": { + "string-width": "^2.0.0" + } + }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "args": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/args/-/args-3.0.2.tgz", + "integrity": "sha1-hQu46IHzE5IDpeTLF2QxCStWLC0=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "4.1.0", + "chalk": "1.1.3", + "minimist": "1.2.0", + "pkginfo": "0.4.0", + "string-similarity": "1.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "optional": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "optional": true, + "requires": { + "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" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "optional": true + } + } + }, + "argv": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/argv/-/argv-0.0.2.tgz", + "integrity": "sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas=", + "dev": true + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-differ": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "dev": true + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, + "array-filter": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", + "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "dev": true + }, + "array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", + "dev": true + }, + "array-map": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", + "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", + "dev": true + }, + "array-reduce": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", + "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "async-to-gen": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-to-gen/-/async-to-gen-1.3.3.tgz", + "integrity": "sha1-1SyftIAfDfRKvE0t4YcLSLYOILs=", + "dev": true, + "optional": true, + "requires": { + "babylon": "^6.14.0", + "magic-string": "^0.19.0" + }, + "dependencies": { + "magic-string": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.19.1.tgz", + "integrity": "sha1-FNdoATyvLsj96hakmvgvw3fnUgE=", + "dev": true, + "optional": true, + "requires": { + "vlq": "^0.2.1" + } + } + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "atob-lite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz", + "integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "babel-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", + "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", + "dev": true, + "requires": { + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/babel__core": "^7.1.0", + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.9.0", + "chalk": "^2.4.2", + "slash": "^2.0.0" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } + } + }, + "babel-plugin-istanbul": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", + "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.3.0", + "test-exclude": "^5.2.3" + } + }, + "babel-plugin-jest-hoist": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", + "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", + "dev": true, + "requires": { + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", + "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", + "dev": true, + "requires": { + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.9.0" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true, + "optional": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "dev": true + }, + "basic-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", + "dev": true, + "optional": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "before-after-hook": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-1.4.0.tgz", + "integrity": "sha512-l5r9ir56nda3qu14nAXIlyq1MmUSs0meCIaFAh8HwkFwP1F8eToOuS3ah2VAHHcY04jaYD7FpJC5JTXHYRbkzg==", + "dev": true + }, + "bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", + "dev": true + }, + "bluebird": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", + "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==", + "dev": true + }, + "boxen": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.1.0.tgz", + "integrity": "sha1-sbad1SIwXoB6md7ud329blFnsQI=", + "dev": true, + "optional": true, + "requires": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^1.1.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^0.1.0", + "widest-line": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "optional": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "optional": true, + "requires": { + "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" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "optional": true + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "browser-process-hrtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", + "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", + "dev": true + }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "dev": true, + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "browserstack": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.2.tgz", + "integrity": "sha512-+6AFt9HzhKykcPF79W6yjEUJcdvZOV0lIXdkORXMJftGrDl0OKWqRF4GHqpDNkxiceDT/uB7Fb/aDwktvXX7dg==", + "dev": true, + "requires": { + "https-proxy-agent": "^2.2.1" + } + }, + "browserstack-local": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/browserstack-local/-/browserstack-local-1.4.0.tgz", + "integrity": "sha512-BUJWxIsJkJxqfTPJIvGWTsf+IYSqSFUeFNW9tnuyTG7va/0LkXLhIi/ErFGDle1urQkol48HlQUXj4QrliXFpg==", + "dev": true, + "requires": { + "https-proxy-agent": "^2.2.1", + "is-running": "^2.0.0", + "ps-tree": "=1.1.1", + "sinon": "^1.17.6", + "temp-fs": "^0.9.9" + }, + "dependencies": { + "lolex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz", + "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE=", + "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 <1" + } + } + } + }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "btoa-lite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", + "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=", + "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": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", + "dev": true + }, + "byline": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", + "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=", + "dev": true + }, + "byte-size": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-4.0.4.tgz", + "integrity": "sha512-82RPeneC6nqCdSwCX2hZUz3JPOvN5at/nTEw/CMf05Smu3Hrpo9Psb7LjN+k+XndNArG1EY8L4+BM3aTM4BCvw==", + "dev": true + }, + "bytes": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", + "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=", + "dev": true, + "optional": true + }, + "cacache": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", + "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + } + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + }, + "dependencies": { + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + } + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "camelcase-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", + "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "map-obj": "^2.0.0", + "quick-lru": "^1.0.0" + } + }, + "capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "requires": { + "rsvp": "^4.8.4" + } + }, + "capture-stack-trace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", + "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", + "dev": true, + "optional": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "optional": true, + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, + "chai": { + "version": "4.2.0", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "chownr": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", + "dev": true + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cli-boxes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", + "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", + "dev": true, + "optional": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "clipboardy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-1.1.4.tgz", + "integrity": "sha1-UbF1dPxoJYji3Slc+m5qoQnqte4=", + "dev": true, + "optional": true, + "requires": { + "execa": "^0.6.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "optional": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.6.3.tgz", + "integrity": "sha1-V7aaWU8IF1nGnlNw8NF7nLEWWP4=", + "dev": true, + "optional": true, + "requires": { + "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" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true, + "optional": true + } + } + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, + "cmd-shim": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-2.1.0.tgz", + "integrity": "sha512-A5C0Cyf2H8sKsHqX0tvIWRXw5/PK++3Dc0lDbsugr90nOECLLuSPahVQBG8pgmgiXgm/TzBWMqI2rWdZwHduAw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "mkdirp": "~0.5.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": 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 + }, + "codecov": { + "version": "3.3.0", + "dev": true, + "requires": { + "argv": "^0.0.2", + "ignore-walk": "^3.0.1", + "js-yaml": "^3.12.0", + "teeny-request": "^3.7.0", + "urlgrey": "^0.4.4" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "columnify": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz", + "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=", + "dev": true, + "requires": { + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "dev": true, + "optional": true + }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "dev": true + }, + "compare-func": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.2.tgz", + "integrity": "sha1-md0LpFfh+bxyKxLAjsM+6rMfpkg=", + "dev": true, + "requires": { + "array-ify": "^1.0.0", + "dot-prop": "^3.0.0" + }, + "dependencies": { + "dot-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz", + "integrity": "sha1-G3CK8JSknJoOfbyteQq6U52sEXc=", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + } + } + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "compressible": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.15.tgz", + "integrity": "sha512-4aE67DL33dSW9gw4CI2H/yTxqHLNcxp0yS6jB+4h+wr3e43+1z7vm0HU9qXOH8j+qjKuL8+UtkOxYQSMq60Ylw==", + "dev": true, + "requires": { + "mime-db": ">= 1.36.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "optional": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true, + "optional": true + }, + "compressible": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz", + "integrity": "sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==", + "dev": true, + "optional": true, + "requires": { + "mime-db": ">= 1.40.0 < 2" + } + } + } + }, + "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 + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "config-chain": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "configstore": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", + "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "dev": true, + "optional": true, + "requires": { + "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" + } + }, + "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 + }, + "conventional-changelog-angular": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.6.tgz", + "integrity": "sha512-QDEmLa+7qdhVIv8sFZfVxU1VSyVvnXPsxq8Vam49mKUcO1Z8VTLEJk9uI21uiJUsnmm0I4Hrsdc9TgkOQo9WSA==", + "dev": true, + "requires": { + "compare-func": "^1.3.1", + "q": "^1.5.1" + } + }, + "conventional-changelog-core": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-3.2.3.tgz", + "integrity": "sha512-LMMX1JlxPIq/Ez5aYAYS5CpuwbOk6QFp8O4HLAcZxe3vxoCtABkhfjetk8IYdRB9CDQGwJFLR3Dr55Za6XKgUQ==", + "dev": true, + "requires": { + "conventional-changelog-writer": "^4.0.6", + "conventional-commits-parser": "^3.0.3", + "dateformat": "^3.0.0", + "get-pkg-repo": "^1.0.0", + "git-raw-commits": "2.0.0", + "git-remote-origin-url": "^2.0.0", + "git-semver-tags": "^2.0.3", + "lodash": "^4.2.1", + "normalize-package-data": "^2.3.5", + "q": "^1.5.1", + "read-pkg": "^3.0.0", + "read-pkg-up": "^3.0.0", + "through2": "^3.0.0" + } + }, + "conventional-changelog-preset-loader": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.0.tgz", + "integrity": "sha512-/rHb32J2EJnEXeK4NpDgMaAVTFZS3o1ExmjKMtYVgIC4MQn0vkNSbYpdGRotkfGGRWiqk3Ri3FBkiZGbAfIfOQ==", + "dev": true + }, + "conventional-changelog-writer": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.11.tgz", + "integrity": "sha512-g81GQOR392I+57Cw3IyP1f+f42ME6aEkbR+L7v1FBBWolB0xkjKTeCWVguzRrp6UiT1O6gBpJbEy2eq7AnV1rw==", + "dev": true, + "requires": { + "compare-func": "^1.3.1", + "conventional-commits-filter": "^2.0.2", + "dateformat": "^3.0.0", + "handlebars": "^4.4.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.15", + "meow": "^5.0.0", + "semver": "^6.0.0", + "split": "^1.0.0", + "through2": "^3.0.0" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "requires": { + "through": "2" + } + } + } + }, + "conventional-commits-filter": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.2.tgz", + "integrity": "sha512-WpGKsMeXfs21m1zIw4s9H5sys2+9JccTzpN6toXtxhpw2VNF2JUXwIakthKBy+LN4DvJm+TzWhxOMWOs1OFCFQ==", + "dev": true, + "requires": { + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.0" + } + }, + "conventional-commits-parser": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.8.tgz", + "integrity": "sha512-YcBSGkZbYp7d+Cr3NWUeXbPDFUN6g3SaSIzOybi8bjHL5IJ5225OSCxJJ4LgziyEJ7AaJtE9L2/EU6H7Nt/DDQ==", + "dev": true, + "requires": { + "JSONStream": "^1.0.4", + "is-text-path": "^1.0.1", + "lodash": "^4.17.15", + "meow": "^5.0.0", + "split2": "^2.0.0", + "through2": "^3.0.0", + "trim-off-newlines": "^1.0.0" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } + } + }, + "conventional-recommended-bump": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-4.1.1.tgz", + "integrity": "sha512-JT2vKfSP9kR18RXXf55BRY1O3AHG8FPg5btP3l7LYfcWJsiXI6MCf30DepQ98E8Qhowvgv7a8iev0J1bEDkTFA==", + "dev": true, + "requires": { + "concat-stream": "^2.0.0", + "conventional-changelog-preset-loader": "^2.1.1", + "conventional-commits-filter": "^2.0.2", + "conventional-commits-parser": "^3.0.2", + "git-raw-commits": "2.0.0", + "git-semver-tags": "^2.0.2", + "meow": "^4.0.0", + "q": "^1.5.1" + }, + "dependencies": { + "concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "meow": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", + "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==", + "dev": true, + "requires": { + "camelcase-keys": "^4.0.0", + "decamelize-keys": "^1.0.0", + "loud-rejection": "^1.0.0", + "minimist": "^1.1.3", + "minimist-options": "^3.0.1", + "normalize-package-data": "^2.3.4", + "read-pkg-up": "^3.0.0", + "redent": "^2.0.0", + "trim-newlines": "^2.0.0" + } + }, + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-js": { + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz", + "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==", + "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 + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "dependencies": { + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } + } + }, + "create-error-class": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "dev": true, + "optional": true, + "requires": { + "capture-stack-trace": "^1.0.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + } + } + }, + "cross-spawn-async": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz", + "integrity": "sha1-hF/wwINKPe2dFg2sptOQkGuyiMw=", + "dev": true, + "optional": true, + "requires": { + "lru-cache": "^4.0.0", + "which": "^1.2.8" + } + }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true + }, + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "cssstyle": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", + "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", + "dev": true, + "requires": { + "cssom": "0.3.x" + } + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "danger": { + "version": "7.1.3", + "dev": true, + "requires": { + "@babel/polyfill": "^7.2.5", + "@octokit/rest": "^16.14.1", + "chalk": "^2.3.0", + "commander": "^2.18.0", + "debug": "^4.1.1", + "get-stdin": "^6.0.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "hyperlinker": "^1.0.0", + "jsome": "^2.3.25", + "json5": "^2.1.0", + "jsonpointer": "^4.0.1", + "jsonwebtoken": "^8.4.0", + "lodash.find": "^4.6.0", + "lodash.includes": "^4.3.0", + "lodash.isobject": "^3.0.2", + "lodash.keys": "^4.0.8", + "lodash.mapvalues": "^4.6.0", + "lodash.memoize": "^4.1.2", + "memfs-or-file-map-to-github-branch": "^1.1.0", + "micromatch": "^3.1.10", + "node-cleanup": "^2.1.2", + "node-fetch": "^2.3.0", + "override-require": "^1.1.1", + "p-limit": "^2.1.0", + "parse-diff": "^0.5.1", + "parse-git-config": "^2.0.3", + "parse-github-url": "^1.0.2", + "parse-link-header": "^1.0.1", + "pinpoint": "^1.1.0", + "readline-sync": "^1.4.9", + "require-from-string": "^2.0.2", + "rfc6902": "^3.0.1", + "supports-hyperlinks": "^1.0.1" + }, + "dependencies": { + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "danger-plugin-tslint": { + "version": "2.0.0", + "dev": true, + "requires": { + "common-tags": "^1.4.0", + "serve": "^5.1.5" + } + }, + "dargs": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-5.1.0.tgz", + "integrity": "sha1-7H6lDHhWTNNsnV7Bj2Yyn63ieCk=", + "dev": true, + "optional": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + } + }, + "date-and-time": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-0.6.3.tgz", + "integrity": "sha512-lcWy3AXDRJOD7MplwZMmNSRM//kZtJaLz4n6D1P5z9wEmZGBKhJRBIr1Xs9KNQJmdXPblvgffynYji4iylUTcA==", + "dev": true + }, + "dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + } + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "optional": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "deepmerge": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.2.0.tgz", + "integrity": "sha512-6+LuZGU7QCNUnAJyX8cIrlzoEgggTM6B7mm+znKOX4t5ltluT9KLjN6g61ECMS0LTsLW7yDpNoxhix5FZcrIow==", + "dev": true + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": 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 + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, + "optional": true + }, + "deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true, + "optional": true + }, + "detect-indent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=", + "dev": true + }, + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true + }, + "detect-port": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.2.1.tgz", + "integrity": "sha512-2KWLTLsfpi/oYPGNBEniPcFzr1GW/s+Xq/4hJmTQRdE8ULuRwGnRPuVhS/cf+Z4ZEXNo7EO2f6oydHJQd94KMg==", + "dev": true, + "optional": true, + "requires": { + "address": "^1.0.1", + "debug": "^2.6.0" + } + }, + "dezalgo": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", + "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "diff-sequences": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", + "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", + "dev": true + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + } + }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "requires": { + "webidl-conversions": "^4.0.2" + } + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "dev": true + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true, + "optional": true + }, + "duplexify": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz", + "integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.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==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true, + "optional": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true, + "optional": true + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "dev": true, + "requires": { + "iconv-lite": "~0.4.13" + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true + }, + "err-code": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", + "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true, + "optional": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escodegen": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", + "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", + "dev": true, + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true, + "optional": true + }, + "event-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "dev": true, + "requires": { + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", + "pause-stream": "0.0.11", + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" + } + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true + }, + "exec-sh": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", + "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", + "dev": true + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.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": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "expect": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", + "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-styles": "^3.2.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.9.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + }, + "dependencies": { + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fast-text-encoding": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz", + "integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==", + "dev": true + }, + "fb-watchman": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", + "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", + "dev": true, + "requires": { + "bser": "^2.0.0" + } + }, + "figgy-pudding": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "filesize": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.5.10.tgz", + "integrity": "sha1-/I+iPdtO+eXgq24eZPZ5okpWdh8=", + "dev": true, + "optional": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + } + } + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "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 + }, + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "formatio": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz", + "integrity": "sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=", + "dev": true, + "requires": { + "samsam": "~1.1" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", + "dev": true + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-exists-sync": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", + "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=", + "dev": true + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "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.0" + } + }, + "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.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "gaxios": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-1.8.4.tgz", + "integrity": "sha512-BoENMnu1Gav18HcpV9IleMPZ9exM+AvUjrAOV4Mzs/vfz2Lu/ABv451iEXByKiMPn2M140uul1txXCg83sAENw==", + "dev": true, + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^2.2.1", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-1.0.0.tgz", + "integrity": "sha512-Q6HrgfrCQeEircnNP3rCcEgiDv7eF9+1B+1MMgpE190+/+0mjQR8PxeOaRgxZWmdDAF9EIryHB9g1moPiw1SbQ==", + "dev": true, + "requires": { + "gaxios": "^1.0.2", + "json-bigint": "^0.3.0" + } + }, + "gcs-resumable-upload": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/gcs-resumable-upload/-/gcs-resumable-upload-1.1.0.tgz", + "integrity": "sha512-uBz7uHqp44xjSDzG3kLbOYZDjxxR/UAGbB47A0cC907W6yd2LkcyFDTHg+bjivkHMwiJlKv4guVWcjPCk2zScg==", + "dev": true, + "requires": { + "abort-controller": "^2.0.2", + "configstore": "^4.0.0", + "gaxios": "^1.5.0", + "google-auth-library": "^3.0.0", + "pumpify": "^1.5.1", + "stream-events": "^1.0.4" + }, + "dependencies": { + "abort-controller": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-2.0.3.tgz", + "integrity": "sha512-EPSq5wr2aFyAZ1PejJB32IX9Qd4Nwus+adnp7STYFM5/23nLPBazqZ1oor6ZqbH+4otaaGXTlC8RN5hq3C8w9Q==", + "dev": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "configstore": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-4.0.0.tgz", + "integrity": "sha512-CmquAXFBocrzaSM8mtGPMM/HiWmyIpr4CcJl/rgY2uCObZ/S7cKU0silxslqJejl+t/T9HS8E0PUNQD81JGUEQ==", + "dev": true, + "requires": { + "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" + } + } + } + }, + "genfun": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", + "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "get-pkg-repo": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-1.4.0.tgz", + "integrity": "sha1-xztInAbYDMVTbCyFP54FIyBWly0=", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "meow": "^3.3.0", + "normalize-package-data": "^2.3.0", + "parse-github-repo-url": "^1.3.0", + "through2": "^2.0.0" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + } + } + }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=", + "dev": true + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "git-config-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/git-config-path/-/git-config-path-1.0.1.tgz", + "integrity": "sha1-bTP37WPbDQ4RgTFQO6s6ykfVRmQ=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "fs-exists-sync": "^0.1.0", + "homedir-polyfill": "^1.0.0" + } + }, + "git-raw-commits": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.0.tgz", + "integrity": "sha512-w4jFEJFgKXMQJ0H0ikBk2S+4KP2VEjhCvLCNqbNRQC8BgGWgLKNCO7a9K9LI+TVT7Gfoloje502sEnctibffgg==", + "dev": true, + "requires": { + "dargs": "^4.0.1", + "lodash.template": "^4.0.2", + "meow": "^4.0.0", + "split2": "^2.0.0", + "through2": "^2.0.0" + }, + "dependencies": { + "dargs": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-4.1.0.tgz", + "integrity": "sha1-A6nbtLXC8Tm/FK5T8LiipqhvThc=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "meow": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", + "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==", + "dev": true, + "requires": { + "camelcase-keys": "^4.0.0", + "decamelize-keys": "^1.0.0", + "loud-rejection": "^1.0.0", + "minimist": "^1.1.3", + "minimist-options": "^3.0.1", + "normalize-package-data": "^2.3.4", + "read-pkg-up": "^3.0.0", + "redent": "^2.0.0", + "trim-newlines": "^2.0.0" + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } + } + }, + "git-remote-origin-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", + "integrity": "sha1-UoJlna4hBxRaERJhEq0yFuxfpl8=", + "dev": true, + "requires": { + "gitconfiglocal": "^1.0.0", + "pify": "^2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "git-semver-tags": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-2.0.3.tgz", + "integrity": "sha512-tj4FD4ww2RX2ae//jSrXZzrocla9db5h0V7ikPl1P/WwoZar9epdUhwR7XHXSgc+ZkNq72BEEerqQuicoEQfzA==", + "dev": true, + "requires": { + "meow": "^4.0.0", + "semver": "^6.0.0" + }, + "dependencies": { + "meow": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", + "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==", + "dev": true, + "requires": { + "camelcase-keys": "^4.0.0", + "decamelize-keys": "^1.0.0", + "loud-rejection": "^1.0.0", + "minimist": "^1.1.3", + "minimist-options": "^3.0.1", + "normalize-package-data": "^2.3.4", + "read-pkg-up": "^3.0.0", + "redent": "^2.0.0", + "trim-newlines": "^2.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "git-up": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-4.0.1.tgz", + "integrity": "sha512-LFTZZrBlrCrGCG07/dm1aCjjpL1z9L3+5aEeI9SBhAqSc+kiA9Or1bgZhQFNppJX6h/f5McrvJt1mQXTFm6Qrw==", + "dev": true, + "requires": { + "is-ssh": "^1.3.0", + "parse-url": "^5.0.0" + } + }, + "git-url-parse": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.1.2.tgz", + "integrity": "sha512-gZeLVGY8QVKMIkckncX+iCq2/L8PlwncvDFKiWkBn9EtCfYDbliRTTp6qzyQ1VMdITUfq7293zDzfpjdiGASSQ==", + "dev": true, + "requires": { + "git-up": "^4.0.0" + } + }, + "gitconfiglocal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", + "integrity": "sha1-QdBF84UaXqiPA/JMocYXgRRGS5s=", + "dev": true, + "requires": { + "ini": "^1.3.2" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "google-auth-library": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-3.1.2.tgz", + "integrity": "sha512-cDQMzTotwyWMrg5jRO7q0A4TL/3GWBgO7I7q5xGKNiiFf9SmGY/OJ1YsLMgI2MVHHsEGyrqYnbnmV1AE+Z6DnQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.0", + "fast-text-encoding": "^1.0.0", + "gaxios": "^1.2.1", + "gcp-metadata": "^1.0.0", + "gtoken": "^2.3.2", + "https-proxy-agent": "^2.2.1", + "jws": "^3.1.5", + "lru-cache": "^5.0.0", + "semver": "^5.5.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + } + } + }, + "google-p12-pem": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-1.0.4.tgz", + "integrity": "sha512-SwLAUJqUfTB2iS+wFfSS/G9p7bt4eWcc2LyfvmUXe7cWp6p3mpxDo6LLI29MXdU6wvPcQ/up298X7GMC5ylAlA==", + "dev": true, + "requires": { + "node-forge": "^0.8.0", + "pify": "^4.0.0" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "got": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "dev": true, + "optional": true, + "requires": { + "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" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true, + "optional": true + } + } + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "gtoken": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-2.3.3.tgz", + "integrity": "sha512-EaB49bu/TCoNeQjhCYKI/CurooBKkGxIqFHsWABW0b25fobBYVTMe84A8EBVVZhl8emiUdNypil9huMOTmyAnw==", + "dev": true, + "requires": { + "gaxios": "^1.0.4", + "google-p12-pem": "^1.0.0", + "jws": "^3.1.5", + "mime": "^2.2.0", + "pify": "^4.0.0" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "handlebars": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", + "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "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 + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-stream-validation": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.1.tgz", + "integrity": "sha1-7Mm5l7IYvluzEphii7gHhptz3NE=", + "dev": true, + "requires": { + "through2": "^2.0.0" + }, + "dependencies": { + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "highlight.js": { + "version": "9.14.2", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.14.2.tgz", + "integrity": "sha512-Nc6YNECYpxyJABGYJAyw7dBAYbXEuIzwzkqoJnwbc1nIpCiN+3ioYf0XrBnLiyyG0JLuJhpPtt2iTSbXiKLoyA==", + "dev": true + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "optional": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true, + "optional": true + } + } + }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "hyperlinker": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hyperlinker/-/hyperlinker-1.0.0.tgz", + "integrity": "sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "ignore-walk": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true, + "optional": true + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "init-package-json": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-1.10.3.tgz", + "integrity": "sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw==", + "dev": true, + "requires": { + "glob": "^7.1.1", + "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "1 || 2", + "semver": "2.x || 3.x || 4 || 5", + "validate-npm-package-license": "^3.0.1", + "validate-npm-package-name": "^3.0.0" + } + }, + "inquirer": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-async-supported": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-async-supported/-/is-async-supported-1.2.0.tgz", + "integrity": "sha1-INWKxNZwfrHLNxLdOEgMBTbyfAc=", + "dev": true, + "optional": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-generator-function": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz", + "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==", + "dev": true + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + }, + "is-npm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", + "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", + "dev": true, + "optional": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", + "dev": true, + "optional": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true, + "optional": true + }, + "is-running": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-running/-/is-running-2.1.0.tgz", + "integrity": "sha1-MKc/9cw4VOT8JUkICen1q/jeCeA=", + "dev": true + }, + "is-ssh": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.1.tgz", + "integrity": "sha512-0eRIASHZt1E68/ixClI8bp2YK2wmBPVWEismTs6M+M099jKgrzl/3E976zIbImSIob48N2/XGe9y7ZiYdImSlg==", + "dev": true, + "requires": { + "protocols": "^1.1.0" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-stream-ended": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", + "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + }, + "dependencies": { + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + } + } + }, + "is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", + "dev": true, + "requires": { + "text-extensions": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "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 + }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", + "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "dev": true, + "requires": { + "handlebars": "^4.1.2" + }, + "dependencies": { + "handlebars": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", + "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + } + } + } + }, + "jest": { + "version": "24.7.1", + "dev": true, + "requires": { + "import-local": "^2.0.0", + "jest-cli": "^24.7.1" + }, + "dependencies": { + "jest-cli": { + "version": "24.7.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.7.1.tgz", + "integrity": "sha512-32OBoSCVPzcTslGFl6yVCMzB2SqX3IrWwZCY5mZYkb0D2WsogmU3eV2o8z7+gRQa4o4sZPX/k7GU+II7CxM6WQ==", + "dev": true, + "requires": { + "@jest/core": "^24.7.1", + "@jest/test-result": "^24.7.1", + "@jest/types": "^24.7.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "import-local": "^2.0.0", + "is-ci": "^2.0.0", + "jest-config": "^24.7.1", + "jest-util": "^24.7.1", + "jest-validate": "^24.7.0", + "prompts": "^2.0.1", + "realpath-native": "^1.1.0", + "yargs": "^12.0.2" + } + } + } + }, + "jest-changed-files": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", + "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "execa": "^1.0.0", + "throat": "^4.0.0" + } + }, + "jest-config": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", + "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^24.9.0", + "@jest/types": "^24.9.0", + "babel-jest": "^24.9.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.9.0", + "jest-environment-node": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.9.0", + "realpath-native": "^1.1.0" + } + }, + "jest-diff": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", + "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "diff-sequences": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-docblock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", + "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", + "dev": true, + "requires": { + "detect-newline": "^2.1.0" + } + }, + "jest-each": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", + "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-environment-jsdom": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", + "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0", + "jsdom": "^11.5.1" + }, + "dependencies": { + "jsdom": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "xml-name-validator": "^3.0.0" + } + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "jest-environment-node": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", + "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0" + } + }, + "jest-get-type": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "dev": true + }, + "jest-haste-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", + "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "anymatch": "^2.0.0", + "fb-watchman": "^2.0.0", + "fsevents": "^1.2.7", + "graceful-fs": "^4.1.15", + "invariant": "^2.2.4", + "jest-serializer": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.9.0", + "micromatch": "^3.1.10", + "sane": "^4.0.3", + "walker": "^1.0.7" + } + }, + "jest-jasmine2": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", + "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^24.9.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0", + "throat": "^4.0.0" + } + }, + "jest-leak-detector": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", + "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", + "dev": true, + "requires": { + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-matcher-utils": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", + "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-message-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } + } + }, + "jest-mock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", + "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0" + } + }, + "jest-pnp-resolver": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", + "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", + "dev": true + }, + "jest-regex-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", + "dev": true + }, + "jest-resolve": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", + "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + } + }, + "jest-resolve-dependencies": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", + "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-snapshot": "^24.9.0" + } + }, + "jest-runner": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", + "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", + "dev": true, + "requires": { + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.4.2", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-docblock": "^24.3.0", + "jest-haste-map": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-leak-detector": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "source-map-support": "^0.5.6", + "throat": "^4.0.0" + } + }, + "jest-runtime": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", + "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", + "dev": true, + "requires": { + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/source-map": "^24.3.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "strip-bom": "^3.0.0", + "yargs": "^13.3.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "jest-serializer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", + "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", + "dev": true + }, + "jest-snapshot": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", + "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "expect": "^24.9.0", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^24.9.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "jest-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", + "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "dev": true, + "requires": { + "@jest/console": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/source-map": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "callsites": "^3.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.15", + "is-ci": "^2.0.0", + "mkdirp": "^0.5.1", + "slash": "^2.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } + } + }, + "jest-validate": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", + "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "camelcase": "^5.3.1", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "leven": "^3.1.0", + "pretty-format": "^24.9.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } + } + }, + "jest-watcher": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", + "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", + "dev": true, + "requires": { + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "jest-util": "^24.9.0", + "string-length": "^2.0.0" + } + }, + "jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", + "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsome": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/jsome/-/jsome-2.5.0.tgz", + "integrity": "sha1-XkF+70NB/+uD7ov6kmWzbVb+Se0=", + "dev": true, + "requires": { + "chalk": "^2.3.0", + "json-stringify-safe": "^5.0.1", + "yargs": "^11.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.1.tgz", + "integrity": "sha512-PRU7gJrJaXv3q3yQZ/+/X6KBswZiaQ+zOmdprZcouPYtQgvNU35i+68M4b1ZHLZtYFT5QObFLV+ZkmJYcwKdiw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" + } + }, + "yargs-parser": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", + "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "json-bigint": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.0.tgz", + "integrity": "sha1-DM2RLEuCcNBfBW+9E4FLU9OCWx4=", + "dev": true, + "requires": { + "bignumber.js": "^7.0.0" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": 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 + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "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 + }, + "json5": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true + }, + "jsonwebtoken": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.4.0.tgz", + "integrity": "sha512-coyXjRTCy0pw5WYBpMvWOMN+Kjaik2MwTUIq9cna/W7NpO9E+iYbumZONAz3hcr+tXFJECoQVrtmIoC3Oz0gvg==", + "dev": true, + "requires": { + "jws": "^3.1.5", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "just-extend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", + "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==", + "dev": true + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dev": true, + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dev": true, + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "karma-browserstack-launcher": { + "version": "1.5.1", + "dev": true, + "requires": { + "browserstack": "~1.5.1", + "browserstack-local": "^1.3.7", + "q": "~1.5.0" + } + }, + "karma-firefox-launcher": { + "version": "1.1.0", + "dev": true + }, + "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.5" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "latest-version": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", + "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "dev": true, + "optional": true, + "requires": { + "package-json": "^4.0.0" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true, + "optional": true + }, + "lazy-req": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lazy-req/-/lazy-req-2.0.0.tgz", + "integrity": "sha1-yUUKNj7N2i5vDHATKtTzf48G8rQ=", + "dev": true, + "optional": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", + "dev": true + }, + "lerna": { + "version": "3.13.4", + "dev": true, + "requires": { + "@lerna/add": "3.13.3", + "@lerna/bootstrap": "3.13.3", + "@lerna/changed": "3.13.4", + "@lerna/clean": "3.13.3", + "@lerna/cli": "3.13.0", + "@lerna/create": "3.13.3", + "@lerna/diff": "3.13.3", + "@lerna/exec": "3.13.3", + "@lerna/import": "3.13.4", + "@lerna/init": "3.13.3", + "@lerna/link": "3.13.3", + "@lerna/list": "3.13.3", + "@lerna/publish": "3.13.4", + "@lerna/run": "3.13.3", + "@lerna/version": "3.13.4", + "import-local": "^1.0.0", + "npmlog": "^4.1.2" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "import-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", + "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", + "dev": true, + "requires": { + "pkg-dir": "^2.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + } + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "libnpmaccess": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-3.0.2.tgz", + "integrity": "sha512-01512AK7MqByrI2mfC7h5j8N9V4I7MHJuk9buo8Gv+5QgThpOgpjB7sQBDDkeZqRteFb1QM/6YNdHfG7cDvfAQ==", + "dev": true, + "requires": { + "aproba": "^2.0.0", + "get-stream": "^4.0.0", + "npm-package-arg": "^6.1.0", + "npm-registry-fetch": "^4.0.0" + }, + "dependencies": { + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + } + } + }, + "libnpmpublish": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-1.1.3.tgz", + "integrity": "sha512-/3LsYqVc52cHXBmu26+J8Ed7sLs/hgGVFMH1mwYpL7Qaynb9RenpKqIKu0sJ130FB9PMkpMlWjlbtU8A4m7CQw==", + "dev": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.0.0", + "lodash.clonedeep": "^4.5.0", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.1.0", + "npm-registry-fetch": "^4.0.0", + "semver": "^5.5.1", + "ssri": "^6.0.1" + }, + "dependencies": { + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + } + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.find": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz", + "integrity": "sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=", + "dev": true + }, + "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.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=", + "dev": true + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=", + "dev": true + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=", + "dev": true + }, + "lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=", + "dev": true + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=", + "dev": true + }, + "lodash.isobject": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", + "integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=", + "dev": true + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", + "dev": true + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", + "dev": true + }, + "lodash.keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-4.2.0.tgz", + "integrity": "sha1-oIYCrBLk+4P5H8H7ejYKTZujUgU=", + "dev": true + }, + "lodash.mapvalues": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz", + "integrity": "sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", + "dev": true + }, + "lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=", + "dev": true + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, + "lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "lolex": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.0.1.tgz", + "integrity": "sha512-UHuOBZ5jjsKuzbB/gRNNW8Vg8f00Emgskdq2kvZxgBJCS0aqquAuXai/SkWORlKeZEiNQWZjFZOqIUcH9LqKCw==", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true, + "optional": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true, + "optional": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + }, + "dependencies": { + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "macos-release": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.3.0.tgz", + "integrity": "sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==", + "dev": true + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "dev": true + }, + "make-fetch-happen": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz", + "integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==", + "dev": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^12.0.0", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + } + } + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.x" + } + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", + "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", + "dev": true + }, + "map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "marked": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.4.0.tgz", + "integrity": "sha512-tMsdNBgOsrUophCAFQl0XPe6Zqk/uy9gnue+jIIKhykO51hxyu6uNx7zBPy0+y/WKYVZZMspV9YeXLNdKk+iYw==", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true, + "optional": true + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + } + } + }, + "memfs-or-file-map-to-github-branch": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/memfs-or-file-map-to-github-branch/-/memfs-or-file-map-to-github-branch-1.1.2.tgz", + "integrity": "sha512-D2JKK2DTuVYQqquBWco3K6UfSVyVwmd58dgNqh+TgxHOZdTmR8I130gjMbVCkemDl/EzqDA62417cJxKL3/FFA==", + "dev": true + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", + "dev": true + }, + "meow": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz", + "integrity": "sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==", + "dev": true, + "requires": { + "camelcase-keys": "^4.0.0", + "decamelize-keys": "^1.0.0", + "loud-rejection": "^1.0.0", + "minimist-options": "^3.0.1", + "normalize-package-data": "^2.3.4", + "read-pkg-up": "^3.0.0", + "redent": "^2.0.0", + "trim-newlines": "^2.0.0", + "yargs-parser": "^10.0.0" + }, + "dependencies": { + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", + "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==", + "dev": true + }, + "micro": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/micro/-/micro-7.3.3.tgz", + "integrity": "sha1-gmHFbSoxp9+TmG7/hkQTlvK0sHA=", + "dev": true, + "optional": true, + "requires": { + "args": "2.6.1", + "async-to-gen": "1.3.3", + "bluebird": "3.5.0", + "boxen": "1.1.0", + "chalk": "1.1.3", + "clipboardy": "1.1.1", + "get-port": "3.1.0", + "ip": "1.1.5", + "is-async-supported": "1.2.0", + "isstream": "0.1.2", + "media-typer": "0.3.0", + "node-version": "1.0.0", + "raw-body": "2.2.0", + "update-notifier": "2.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "optional": true + }, + "args": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/args/-/args-2.6.1.tgz", + "integrity": "sha1-slkO1BaM0xtiREGZvcUWa7GSDC8=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "4.1.0", + "chalk": "1.1.3", + "minimist": "1.2.0", + "pkginfo": "0.4.0", + "string-similarity": "1.1.0" + } + }, + "bluebird": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", + "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=", + "dev": true, + "optional": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "optional": true, + "requires": { + "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" + } + }, + "clipboardy": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-1.1.1.tgz", + "integrity": "sha1-dbWnrFDYPJgCX7YwMpjGqQB8Fsc=", + "dev": true, + "optional": true, + "requires": { + "execa": "^0.6.0" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "optional": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.6.3.tgz", + "integrity": "sha1-V7aaWU8IF1nGnlNw8NF7nLEWWP4=", + "dev": true, + "optional": true, + "requires": { + "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" + } + }, + "get-port": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.1.0.tgz", + "integrity": "sha1-7wGxioTKZIaXD/meVERhQac//T4=", + "dev": true, + "optional": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true, + "optional": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "optional": true + }, + "update-notifier": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.1.0.tgz", + "integrity": "sha1-7AweU1NrdmR6JLd8uDlm2TFRI9k=", + "dev": true, + "optional": true, + "requires": { + "boxen": "^1.0.0", + "chalk": "^1.0.0", + "configstore": "^3.0.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "lazy-req": "^2.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + } + } + }, + "micro-compress": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micro-compress/-/micro-compress-1.0.0.tgz", + "integrity": "sha1-U/WoC0rQMgyhZaVZtuPfFF1PcE8=", + "dev": true, + "optional": true, + "requires": { + "compression": "^1.6.2" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "dev": true + }, + "mime-db": { + "version": "1.42.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", + "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.25", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", + "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", + "dev": true, + "requires": { + "mime-db": "1.42.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "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": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "minimist-options": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", + "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0" + } + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + }, + "dependencies": { + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "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" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "mocha": { + "version": "6.1.4", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "2.2.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "ms": "2.1.1", + "node-environment-flags": "1.0.5", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.2.2", + "yargs-parser": "13.0.0", + "yargs-unparser": "1.5.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "yargs": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", + "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.0.0" + } + }, + "yargs-parser": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz", + "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "mock-require": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/mock-require/-/mock-require-3.0.3.tgz", + "integrity": "sha512-lLzfLHcyc10MKQnNUCv7dMcoY/2Qxd6wJfbqCcVk3LDb8An4hF6ohk5AztrvgKhJCqj36uyzi/p5se+tvyD+Wg==", + "dev": true, + "requires": { + "get-caller-file": "^1.0.2", + "normalize-path": "^2.1.1" + } + }, + "modify-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", + "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", + "dev": true + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multimatch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", + "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", + "dev": true, + "requires": { + "array-differ": "^1.0.0", + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "minimatch": "^3.0.0" + } + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true, + "optional": true + }, + "neo-async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", + "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "nise": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.10.tgz", + "integrity": "sha512-sa0RRbj53dovjc7wombHmVli9ZihXbXCQ2uH3TNm03DyvOSIQbxg+pbqDKrk2oxMK1rtLGVlKxcB9rrc6X5YjA==", + "dev": true, + "requires": { + "@sinonjs/formatio": "^3.1.0", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "lolex": "^2.3.2", + "path-to-regexp": "^1.7.0" + }, + "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": "2.7.5", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz", + "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==", + "dev": true + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + } + } + }, + "node-cleanup": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz", + "integrity": "sha1-esGavSl+Caf3KnFUXZUbUX5N3iw=", + "dev": true + }, + "node-environment-flags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", + "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", + "dev": true + }, + "node-fetch-npm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz", + "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==", + "dev": true, + "requires": { + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" + } + }, + "node-forge": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.8.5.tgz", + "integrity": "sha512-vFMQIWt+J/7FLNyKouZ9TazT74PRV3wgv9UT4cRjC8BffxFbKXkgIWR42URCPSnHm/QDz6BOlb2Q0U4+VQT67Q==", + "dev": true + }, + "node-gyp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-4.0.0.tgz", + "integrity": "sha512-2XiryJ8sICNo6ej8d0idXDEMKfVfFK7kekGCtJAuelGsYHQxhj13KTf95swTCN2dZ/4lTfZ84Fu31jqJEEgjWA==", + "dev": true, + "requires": { + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^4.4.8", + "which": "1" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + } + } + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, + "node-notifier": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", + "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", + "dev": true, + "requires": { + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.0" + } + }, + "node-version": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-version/-/node-version-1.0.0.tgz", + "integrity": "sha1-G5uVhKmn96YSPyFc0UplK/IasZ4=", + "dev": true, + "optional": true + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", + "dev": true + }, + "npm-bundled": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", + "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", + "dev": true + }, + "npm-lifecycle": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-2.1.1.tgz", + "integrity": "sha512-+Vg6I60Z75V/09pdcH5iUo/99Q/vop35PaI99elvxk56azSVVsdsSsS/sXqKDNwbRRNN1qSxkcO45ZOu0yOWew==", + "dev": true, + "requires": { + "byline": "^5.0.0", + "graceful-fs": "^4.1.15", + "node-gyp": "^4.0.0", + "resolve-from": "^4.0.0", + "slide": "^1.1.6", + "uid-number": "0.0.6", + "umask": "^1.1.0", + "which": "^1.3.1" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "npm-package-arg": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", + "dev": true, + "requires": { + "hosted-git-info": "^2.7.1", + "osenv": "^0.1.5", + "semver": "^5.6.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-packlist": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.6.tgz", + "integrity": "sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg==", + "dev": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npm-pick-manifest": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz", + "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + } + }, + "npm-registry-fetch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.2.tgz", + "integrity": "sha512-Z0IFtPEozNdeZRPh3aHHxdG+ZRpzcbQaJLthsm3VhNf6DScicTFRHZzK82u8RsJUsUHkX+QH/zcB/5pmd20H4A==", + "dev": true, + "requires": { + "JSONStream": "^1.3.4", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.4.1", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "npm-package-arg": "^6.1.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + } + } + }, + "npm-run-all": { + "version": "4.1.5", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + }, + "dependencies": { + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + } + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "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 + }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": 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 + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "object-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", + "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.entries": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", + "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "octokit-pagination-methods": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz", + "integrity": "sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "optional": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "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" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + }, + "dependencies": { + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + } + } + }, + "opn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz", + "integrity": "sha512-iPNl7SyM8L30Rm1sjGdLLheyHVw5YXVfi3SKWJzBI7efxRwHojfRFjwE/OLM6qp9xJYMgab8WicTU1cPoY+Hpg==", + "dev": true, + "optional": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "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.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + } + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "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", + "word-wrap": "~1.2.3" + } + }, + "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 + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "os-name": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz", + "integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==", + "dev": true, + "requires": { + "macos-release": "^2.2.0", + "windows-release": "^3.1.0" + } + }, + "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 + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "override-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/override-require/-/override-require-1.1.1.tgz", + "integrity": "sha1-auIvresfhQ/7DPTCD/e4fl62UN8=", + "dev": true + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "dev": true + }, + "p-map-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-map-series/-/p-map-series-1.0.0.tgz", + "integrity": "sha1-v5j+V1cFZYqeE1G++4WuTB8Hvco=", + "dev": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, + "p-pipe": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-1.2.0.tgz", + "integrity": "sha1-SxoROZoRUgpneQ7loMHViB1r7+k=", + "dev": true + }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "p-waterfall": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-waterfall/-/p-waterfall-1.0.0.tgz", + "integrity": "sha1-ftlLPOszMngjU69qrhGqn8I1uwA=", + "dev": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, + "package-json": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", + "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", + "dev": true, + "optional": true, + "requires": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + } + }, + "pacote": { + "version": "9.5.9", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.9.tgz", + "integrity": "sha512-S1nYW9ly+3btn3VmwRAk2LG3TEh8mkrFdY+psbnHSk8oPODbZ28uG0Z0d3yI0EpqcpLR6BukoVRf3H4IbGCkPQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "cacache": "^12.0.2", + "chownr": "^1.1.2", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.1.0", + "glob": "^7.1.3", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "minimatch": "^3.0.4", + "minipass": "^2.3.5", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.12", + "npm-pick-manifest": "^3.0.0", + "npm-registry-fetch": "^4.0.0", + "osenv": "^0.1.5", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^5.0.1", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.6.0", + "ssri": "^6.0.1", + "tar": "^4.4.10", + "unique-filename": "^1.1.1", + "which": "^1.3.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + } + } + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dev": true, + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "parse-diff": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/parse-diff/-/parse-diff-0.5.1.tgz", + "integrity": "sha512-/qXjo9x/pFa5bVk/ZXaJD0yr3Tf3Yp6MWWMr4vnUmumDrE0yoE6YDH2A8vmcCD/Ko3tW2o0X+zGYh2zMLXshsg==", + "dev": true + }, + "parse-git-config": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/parse-git-config/-/parse-git-config-2.0.3.tgz", + "integrity": "sha512-Js7ueMZOVSZ3tP8C7E3KZiHv6QQl7lnJ+OkbxoaFazzSa2KyEHqApfGbU3XboUgUnq4ZuUmskUpYKTNx01fm5A==", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "git-config-path": "^1.0.1", + "ini": "^1.3.5" + } + }, + "parse-github-repo-url": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz", + "integrity": "sha1-nn2LslKmy2ukJZUGC3v23z28H1A=", + "dev": true + }, + "parse-github-url": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz", + "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parse-link-header": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-link-header/-/parse-link-header-1.0.1.tgz", + "integrity": "sha1-vt/g0hGK64S+deewJUGeyKYRQKc=", + "dev": true, + "requires": { + "xtend": "~4.0.1" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "parse-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.1.tgz", + "integrity": "sha512-d7yhga0Oc+PwNXDvQ0Jv1BuWkLVPXcAoQ/WREgd6vNNoKYaW52KI+RdOFjI63wjkmps9yUE8VS4veP+AgpQ/hA==", + "dev": true, + "requires": { + "is-ssh": "^1.3.0", + "protocols": "^1.4.0" + } + }, + "parse-url": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-5.0.1.tgz", + "integrity": "sha512-flNUPP27r3vJpROi0/R3/2efgKkyXqnXwyP1KQ2U0SfFRgdizOdWfvrrvJg1LuOoxs7GQhmxJlq23IpQ/BkByg==", + "dev": true, + "requires": { + "is-ssh": "^1.3.0", + "normalize-url": "^3.3.0", + "parse-path": "^4.0.0", + "protocols": "^1.4.0" + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "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 + }, + "path-key": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-1.0.0.tgz", + "integrity": "sha1-XVPVeAGWRsDWiADbThRua9wqx68=", + "dev": true, + "optional": true + }, + "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==", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "dev": true, + "requires": { + "through": "~2.3" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "pidtree": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz", + "integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pinpoint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pinpoint/-/pinpoint-1.1.0.tgz", + "integrity": "sha1-DPd1eml38b9/ajIge3CeN3OI6HQ=", + "dev": true + }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "pkginfo": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.0.tgz", + "integrity": "sha1-NJ27f/04CB/K3AhT32h/DHdEzWU=", + "dev": true, + "optional": true + }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "dev": true + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true, + "optional": true + }, + "prettier": { + "version": "1.17.0", + "dev": true + }, + "prettier-check": { + "version": "2.0.0", + "dev": true, + "requires": { + "execa": "^0.6.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.6.3.tgz", + "integrity": "sha1-V7aaWU8IF1nGnlNw8NF7nLEWWP4=", + "dev": true, + "requires": { + "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" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + } + } + }, + "pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "promise-retry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", + "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", + "dev": true, + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + } + }, + "prompts": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.0.tgz", + "integrity": "sha512-NfbbPPg/74fT7wk2XYQ7hAIp9zJyZp5Fu19iRbORqqy1BhtrkZ0fPafBU+7bmn8ie69DpT0R6QpJIN2oisYjJg==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.3" + } + }, + "promzard": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz", + "integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=", + "dev": true, + "requires": { + "read": "1" + } + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true + }, + "protocols": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/protocols/-/protocols-1.4.7.tgz", + "integrity": "sha512-Fx65lf9/YDn3hUX08XUc0J8rSux36rEsyiv21ZGUC1mOyeM3lTRpZLcrm8aAolzS4itwVfm7TAPyxC2E5zd6xg==", + "dev": true + }, + "protoduck": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", + "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", + "dev": true, + "requires": { + "genfun": "^5.0.0" + } + }, + "ps-tree": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.1.1.tgz", + "integrity": "sha512-kef7fYYSKVqQffmzTMsVcUD1ObNJMp8sNSmHGlGKsZQyL/ht9MZKk86u0Rd1NhpTOAuhqwKCLLpktwkqz+MF8A==", + "dev": true, + "requires": { + "event-stream": "=3.3.4" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", + "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "quick-lru": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", + "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", + "dev": true + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "optional": true + }, + "raw-body": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz", + "integrity": "sha1-mUl2z2pQlqQRYoQEkvC9xdbn+5Y=", + "dev": true, + "optional": true, + "requires": { + "bytes": "2.4.0", + "iconv-lite": "0.4.15", + "unpipe": "1.0.0" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", + "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=", + "dev": true, + "optional": true + } + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "react-is": { + "version": "16.12.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", + "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==", + "dev": true + }, + "read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "dev": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "read-cmd-shim": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz", + "integrity": "sha512-v5yCqQ/7okKoZZkBQUAfTsQ3sVJtXdNfbPnI5cceppoxEVLYA3k+VtV2omkeo8MS94JCy4fSiUwlRBAwCVRPUA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2" + } + }, + "read-package-json": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.0.tgz", + "integrity": "sha512-KLhu8M1ZZNkMcrq1+0UJbR8Dii8KZUqB0Sha4mOx/bknfKI/fyrQVrG/YIt2UOtG667sD8+ee4EXMM91W9dC+A==", + "dev": true, + "requires": { + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "json-parse-better-errors": "^1.0.1", + "normalize-package-data": "^2.0.0", + "slash": "^1.0.0" + } + }, + "read-package-tree": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", + "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", + "dev": true, + "requires": { + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.0" + } + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "readline-sync": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.9.tgz", + "integrity": "sha1-PtqOZfI80qF+YTAbHwADOWr17No=", + "dev": true + }, + "realpath-native": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "dev": true, + "requires": { + "util.promisify": "^1.0.0" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "redent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", + "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", + "dev": true, + "requires": { + "indent-string": "^3.0.0", + "strip-indent": "^2.0.0" + } + }, + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==", + "dev": true + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "registry-auth-token": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", + "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", + "dev": true, + "optional": true, + "requires": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "dev": true, + "optional": true, + "requires": { + "rc": "^1.0.1" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "replace-in-file": { + "version": "4.0.0", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "glob": "^7.1.3", + "yargs": "^13.2.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "yargs": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", + "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.0.0" + }, + "dependencies": { + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + } + } + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + } + } + }, + "request-promise-core": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", + "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } + } + }, + "request-promise-native": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", + "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", + "dev": true, + "requires": { + "request-promise-core": "1.1.3", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "resolve": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.0.tgz", + "integrity": "sha512-HHZ3hmOrk5SvybTb18xq4Ek2uLqLO5/goFCYUyvn26nWox4hdlKlfC/+dChIZ6qc4ZeYcN9ekTz0yyHsFgumMw==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "dependencies": { + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + } + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=", + "dev": true + }, + "retry-request": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.1.tgz", + "integrity": "sha512-BINDzVtLI2BDukjWmjAIRZ0oglnCAkpP2vQjM3jdLhmT62h0xnQgciPwBRDAvHqpkPT2Wo1XuUyLyn6nbGrZQQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "through2": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "dev": true, + "requires": { + "readable-stream": "2 || 3" + } + } + } + }, + "rfc6902": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/rfc6902/-/rfc6902-3.0.1.tgz", + "integrity": "sha512-a4t5OlaOgAejBg48/lkyQMcV6EWpljjSjmXAtSXLhw83x1OhlcVGLMLf//GoUSpHsWt8x/7oxaf5FEGM9QH/iQ==", + "dev": true + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "optional": true, + "requires": { + "align-text": "^0.1.1" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "samsam": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz", + "integrity": "sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc=", + "dev": true + }, + "sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "dev": true, + "requires": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true + }, + "semver-diff": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", + "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "dev": true, + "optional": true, + "requires": { + "semver": "^5.0.3" + } + }, + "serve": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/serve/-/serve-5.2.4.tgz", + "integrity": "sha1-R0LAX2WiMw94jN3pAc16CbI6mfY=", + "dev": true, + "optional": true, + "requires": { + "args": "3.0.2", + "basic-auth": "1.1.0", + "bluebird": "3.5.0", + "boxen": "1.1.0", + "chalk": "1.1.3", + "clipboardy": "1.1.4", + "dargs": "5.1.0", + "detect-port": "1.2.1", + "filesize": "3.5.10", + "fs-extra": "3.0.1", + "handlebars": "4.0.10", + "ip": "1.1.5", + "micro": "7.3.3", + "micro-compress": "1.0.0", + "mime-types": "2.1.15", + "node-version": "1.0.0", + "opn": "5.1.0", + "path-type": "2.0.0", + "send": "0.15.3", + "update-notifier": "2.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "optional": true + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true, + "optional": true + }, + "bluebird": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", + "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=", + "dev": true, + "optional": true + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true, + "optional": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "optional": true, + "requires": { + "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": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "optional": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + } + }, + "debug": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", + "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "fresh": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz", + "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44=", + "dev": true, + "optional": true + }, + "fs-extra": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", + "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^3.0.0", + "universalify": "^0.1.0" + } + }, + "handlebars": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz", + "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", + "dev": true, + "optional": true, + "requires": { + "async": "^1.4.0", + "optimist": "^0.6.1", + "source-map": "^0.4.4", + "uglify-js": "^2.6" + } + }, + "jsonfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", + "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "mime": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", + "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=", + "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, + "optional": 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, + "optional": true, + "requires": { + "mime-db": "~1.27.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "optional": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "optional": true + }, + "send": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/send/-/send-0.15.3.tgz", + "integrity": "sha1-UBP5+ZAj31DRvZiSwZ4979HVMwk=", + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.7", + "depd": "~1.1.0", + "destroy": "~1.0.4", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "etag": "~1.8.0", + "fresh": "0.5.0", + "http-errors": "~1.6.1", + "mime": "1.3.4", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.3.1" + } + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "optional": true, + "requires": { + "amdefine": ">=0.0.4" + } + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "dev": true, + "optional": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "optional": true + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "optional": true, + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "optional": true + } + } + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true, + "optional": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + } + } + }, + "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 + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true, + "optional": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shell-quote": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", + "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", + "dev": true, + "requires": { + "array-filter": "~0.0.0", + "array-map": "~0.0.0", + "array-reduce": "~0.0.0", + "jsonify": "~0.0.0" + } + }, + "shelljs": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", + "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": 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 + }, + "sinon": { + "version": "7.3.2", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.4.0", + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/samsam": "^3.3.1", + "diff": "^3.5.0", + "lolex": "^4.0.1", + "nise": "^1.4.10", + "supports-color": "^5.5.0" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.4.0.tgz", + "integrity": "sha512-9jHK3YF/8HtJ9wCAbG+j8cD0i0+ATS9A7gXFqS36TblLPNy6rEEc+SB0imo91eCboGaBYGV/MT1/br/J+EE7Tw==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + } + } + }, + "sisteransi": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.4.tgz", + "integrity": "sha512-/ekMoM4NJ59ivGSfKapeG+FWtrmWvA1p6FBZwXrqojw90vJu8lBmrTxCMuBCydKtkaUe2zt4PlxeTKpjwMbyig==", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "dev": true + }, + "smart-buffer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", + "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==", + "dev": true + }, + "snakeize": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/snakeize/-/snakeize-0.1.0.tgz", + "integrity": "sha1-EMCI2LWOsHazIpu1oE4jLOEmQi0=", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + } + }, + "socks": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", + "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", + "dev": true, + "requires": { + "ip": "1.1.5", + "smart-buffer": "^4.1.0" + } + }, + "socks-proxy-agent": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", + "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", + "dev": true, + "requires": { + "agent-base": "~4.2.1", + "socks": "~2.3.2" + }, + "dependencies": { + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + } + } + }, + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "dev": true, + "requires": { + "through": "2" + } + }, + "split-array-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/split-array-stream/-/split-array-stream-2.0.0.tgz", + "integrity": "sha512-hmMswlVY91WvGMxs0k8MRgq8zb2mSen4FmDNc5AFiTWtrBpdZN6nwD6kROVe4vNL+ywrvbCKsWVCnEd4riELIg==", + "dev": true, + "requires": { + "is-stream-ended": "^0.1.4" + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "split2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", + "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==", + "dev": true, + "requires": { + "through2": "^2.0.2" + }, + "dependencies": { + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true, + "optional": true + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "stream-combiner": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "dev": true, + "requires": { + "duplexer": "~0.1.1" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "dev": true, + "requires": { + "stubs": "^3.0.0" + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true + }, + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string-similarity": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-1.1.0.tgz", + "integrity": "sha1-PGZJiFikZex8QMfYFzm72ZWQSRQ=", + "dev": true, + "optional": true, + "requires": { + "lodash": "^4.13.1" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string.prototype.padend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz", + "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.4.3", + "function-bind": "^1.0.2" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "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.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "dev": true + }, + "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 + }, + "strong-log-transformer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", + "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "minimist": "^1.2.0", + "through": "^2.3.4" + } + }, + "stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-hyperlinks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz", + "integrity": "sha512-HHi5kVSefKaJkGYXbDuKbUGRVxqnWGn3J2e39CYcNJEfWciGq2zYtOhXLTlvrOZW1QU7VX67w7fMmWafHX9Pfw==", + "dev": true, + "requires": { + "has-flag": "^2.0.0", + "supports-color": "^5.0.0" + }, + "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 + } + } + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "teeny-request": { + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-3.11.3.tgz", + "integrity": "sha512-CKncqSF7sH6p4rzCgkb/z/Pcos5efl0DmolzvlqRQUNcpRIruOhY9+T1FsIlyEbfWd7MsFpodROOwHYh2BaXzw==", + "dev": true, + "requires": { + "https-proxy-agent": "^2.2.1", + "node-fetch": "^2.2.0", + "uuid": "^3.3.2" + } + }, + "temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", + "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", + "dev": true + }, + "temp-fs": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/temp-fs/-/temp-fs-0.9.9.tgz", + "integrity": "sha1-gHFzBDeHByDpQxUy/igUNk+IA9c=", + "dev": true, + "requires": { + "rimraf": "~2.5.2" + }, + "dependencies": { + "rimraf": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz", + "integrity": "sha1-loAAk8vxoMhr2VtGJUZ1NcKd+gQ=", + "dev": true, + "requires": { + "glob": "^7.0.5" + } + } + } + }, + "temp-write": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/temp-write/-/temp-write-3.4.0.tgz", + "integrity": "sha1-jP9jD7fp2gXwR8dM5M5NaFRX1JI=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "is-stream": "^1.1.0", + "make-dir": "^1.0.0", + "pify": "^3.0.0", + "temp-dir": "^1.0.0", + "uuid": "^3.0.1" + } + }, + "term-size": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-0.1.1.tgz", + "integrity": "sha1-hzYLljlsq1dgljcUzaDQy+7K2co=", + "dev": true, + "optional": true, + "requires": { + "execa": "^0.4.0" + }, + "dependencies": { + "execa": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.4.0.tgz", + "integrity": "sha1-TrZGejaglfq7KXD/nV4/t7zm68M=", + "dev": true, + "optional": true, + "requires": { + "cross-spawn-async": "^2.1.1", + "is-stream": "^1.1.0", + "npm-run-path": "^1.0.0", + "object-assign": "^4.0.1", + "path-key": "^1.0.0", + "strip-eof": "^1.0.0" + } + }, + "npm-run-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-1.0.0.tgz", + "integrity": "sha1-9cMr9ZX+ga6Sfa7FLoL4sACsPI8=", + "dev": true, + "optional": true, + "requires": { + "path-key": "^1.0.0" + } + } + } + }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "requires": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + }, + "dependencies": { + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + } + } + }, + "text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "dev": true + }, + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.0.tgz", + "integrity": "sha512-8B+sevlqP4OiCjonI1Zw03Sf8PuV1eRsYQgLad5eonILOdyeRsY27A/2Ze8IlvlMvq31OH+3fz/styI7Ya62yQ==", + "dev": true, + "requires": { + "readable-stream": "2 || 3", + "xtend": "~4.0.1" + } + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true, + "optional": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "trim-newlines": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", + "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", + "dev": true + }, + "trim-off-newlines": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz", + "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=", + "dev": true + }, + "ts-jest": { + "version": "24.0.2", + "dev": true, + "requires": { + "bs-logger": "0.x", + "buffer-from": "1.x", + "fast-json-stable-stringify": "2.x", + "json5": "2.x", + "make-error": "1.x", + "mkdirp": "0.x", + "resolve": "1.x", + "semver": "^5.5", + "yargs-parser": "10.x" + }, + "dependencies": { + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "dev": true, + "requires": { + "path-parse": "^1.0.5" + } + } + } + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "tslint": { + "version": "5.16.0", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.13.0", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.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, + "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 + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typedoc": { + "version": "0.14.2", + "dev": true, + "requires": { + "@types/fs-extra": "^5.0.3", + "@types/handlebars": "^4.0.38", + "@types/highlight.js": "^9.12.3", + "@types/lodash": "^4.14.110", + "@types/marked": "^0.4.0", + "@types/minimatch": "3.0.3", + "@types/shelljs": "^0.8.0", + "fs-extra": "^7.0.0", + "handlebars": "^4.0.6", + "highlight.js": "^9.13.1", + "lodash": "^4.17.10", + "marked": "^0.4.0", + "minimatch": "^3.0.0", + "progress": "^2.0.0", + "shelljs": "^0.8.2", + "typedoc-default-themes": "^0.5.0", + "typescript": "3.2.x" + }, + "dependencies": { + "typescript": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.4.tgz", + "integrity": "sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==", + "dev": true + } + } + }, + "typedoc-default-themes": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.5.0.tgz", + "integrity": "sha1-bcJDPnjti+qOiHo6zeLzF4W9Yic=", + "dev": true + }, + "typescript": { + "version": "3.4.5", + "dev": true + }, + "typescript-tslint-plugin": { + "version": "0.3.1", + "dev": true, + "requires": { + "minimatch": "^3.0.4", + "mock-require": "^3.0.2", + "vscode-languageserver": "^5.1.0" + } + }, + "uglify-js": { + "version": "3.4.9", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", + "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.17.1", + "source-map": "~0.6.1" + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "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 + }, + "umask": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz", + "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "dev": true, + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "universal-user-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-2.1.0.tgz", + "integrity": "sha512-8itiX7G05Tu3mGDTdNY2fB4KJ8MgZLS54RdG6PkkfwMAavrXu1mV/lls/GABx9O3Rw4PnTtasxrvbMQoBYY92Q==", + "dev": true, + "requires": { + "os-name": "^3.0.0" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true, + "optional": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "unzip-response": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", + "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", + "dev": true, + "optional": true + }, + "update-notifier": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.2.0.tgz", + "integrity": "sha1-G1g3z5DAc22IYncytmHBOPht5y8=", + "dev": true, + "optional": true, + "requires": { + "boxen": "^1.0.0", + "chalk": "^1.0.0", + "configstore": "^3.0.0", + "import-lazy": "^2.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": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "optional": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "optional": true, + "requires": { + "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" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "optional": true + } + } + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "optional": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, + "url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=", + "dev": true + }, + "urlgrey": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/urlgrey/-/urlgrey-0.4.4.tgz", + "integrity": "sha1-iS/pWWCAXoVRnxzUOJ8stMu3ZS8=", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.1.tgz", + "integrity": "sha512-MREAtYOp+GTt9/+kwf00IYoHZyjM8VU4aVrkzUlejyqaIjd2GztVl5V9hGXKlvBKE3gENn/FMfHE5v6hElXGcQ==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "object.entries": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "util-promisify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", + "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "dev": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true, + "optional": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vlq": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", + "dev": true, + "optional": true + }, + "vscode-jsonrpc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz", + "integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg==", + "dev": true + }, + "vscode-languageserver": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-5.2.1.tgz", + "integrity": "sha512-GuayqdKZqAwwaCUjDvMTAVRPJOp/SLON3mJ07eGsx/Iq9HjRymhKWztX41rISqDKhHVVyFM+IywICyZDla6U3A==", + "dev": true, + "requires": { + "vscode-languageserver-protocol": "3.14.1", + "vscode-uri": "^1.0.6" + } + }, + "vscode-languageserver-protocol": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz", + "integrity": "sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g==", + "dev": true, + "requires": { + "vscode-jsonrpc": "^4.0.0", + "vscode-languageserver-types": "3.14.0" + } + }, + "vscode-languageserver-types": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz", + "integrity": "sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A==", + "dev": true + }, + "vscode-uri": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.8.tgz", + "integrity": "sha512-obtSWTlbJ+a+TFRYGaUumtVwb+InIUVI0Lu0VBUAPmj2cU5JutEXg3xUE0c2J5Tcy7h2DEKVJBFi+Y9ZSFzzPQ==", + "dev": true + }, + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "dev": true, + "requires": { + "browser-process-hrtime": "^0.1.2" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.x" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", + "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "widest-line": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-1.0.0.tgz", + "integrity": "sha1-DAnIXCqUaD0Nfq+O4JfVZL8OEFw=", + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.1" + }, + "dependencies": { + "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, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true, + "optional": true + }, + "windows-release": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.1.0.tgz", + "integrity": "sha512-hBb7m7acFgQPQc222uEQTmdcGLeBmQLNLFIh0rDk3CwFOBrfjefLzEfEfmpMq8Af/n/GnFf3eYf203FY1PmudA==", + "dev": true, + "requires": { + "execa": "^0.10.0" + }, + "dependencies": { + "execa": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", + "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "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" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + } + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "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.0" + } + }, + "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.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz", + "integrity": "sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "write-json-file": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-2.3.0.tgz", + "integrity": "sha1-K2TIozAE1UuGmMdtWFp3zrYdoy8=", + "dev": true, + "requires": { + "detect-indent": "^5.0.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "pify": "^3.0.0", + "sort-keys": "^2.0.0", + "write-file-atomic": "^2.0.0" + } + }, + "write-pkg": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/write-pkg/-/write-pkg-3.2.0.tgz", + "integrity": "sha512-tX2ifZ0YqEFOF1wjRW2Pk93NLsj02+n1UP5RvO6rCs0K6R2g1padvf006cY74PQJKMGS2r42NK7FD0dG6Y6paw==", + "dev": true, + "requires": { + "sort-keys": "^2.0.0", + "write-json-file": "^2.2.0" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "dev": true + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.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 || ^4.0.0", + "yargs-parser": "^11.1.1" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + }, + "yargs-unparser": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", + "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.11", + "yargs": "^12.0.5" + } + } + } +} diff --git a/packages/apm/src/hubextensions.ts b/packages/apm/src/hubextensions.ts index e759aacb9ff4..18df0f4d0592 100644 --- a/packages/apm/src/hubextensions.ts +++ b/packages/apm/src/hubextensions.ts @@ -61,7 +61,7 @@ function startSpan(spanOrSpanContext?: Span | SpanContext, forceNoChild: boolean if (span.sampled) { const experimentsOptions = (client && client.getOptions()._experiments) || {}; - span.initFinishedSpans(experimentsOptions.maxSpans); + span.initFinishedSpans(experimentsOptions.maxSpans as number); } return span; diff --git a/packages/apm/src/span.ts b/packages/apm/src/span.ts index f899a57a07de..c4f045e46fc2 100644 --- a/packages/apm/src/span.ts +++ b/packages/apm/src/span.ts @@ -1,9 +1,10 @@ // tslint:disable:max-classes-per-file import { getCurrentHub, Hub } from '@sentry/hub'; -import { Span as SpanInterface, SpanContext } from '@sentry/types'; +import { Span as SpanInterface, SpanContext, SpanStatus } from '@sentry/types'; import { logger, timestampWithMs, uuid4 } from '@sentry/utils'; +// TODO: Should this be exported? export const TRACEPARENT_REGEXP = new RegExp( '^[ \\t]*' + // whitespace '([0-9a-f]{32})?' + // trace_id @@ -227,16 +228,17 @@ export class Span implements SpanInterface, SpanContext { /** * @inheritDoc */ - public setFailure(): this { - this.setTag('status', 'failure'); + public setStatus(value: SpanStatus): this { + this.setTag('status', value); return this; } /** * @inheritDoc */ - public setSuccess(): this { - this.setTag('status', 'success'); + public setHttpStatus(httpStatus: number): this { + this.setTag('http.status_code', String(httpStatus)); + this.setStatus(SpanStatus.fromHttpCode(httpStatus)); return this; } @@ -244,7 +246,7 @@ export class Span implements SpanInterface, SpanContext { * @inheritDoc */ public isSuccess(): boolean { - return this.tags.status !== 'failure'; + return this.tags.status === SpanStatus.Ok; } /** @@ -285,11 +287,10 @@ export class Span implements SpanInterface, SpanContext { } return this._hub.captureEvent({ - // TODO: Is this necessary? We already do store contextx in in applyToEvent, - // so maybe we can move `getTraceContext` call there as well? contexts: { trace: this.getTraceContext() }, spans: finishedSpans, start_timestamp: this.startTimestamp, + tags: this.tags, timestamp: this.timestamp, transaction: this.transaction, type: 'transaction', diff --git a/packages/apm/test/span.test.ts b/packages/apm/test/span.test.ts index da3b3dbeac42..4c4313a998b6 100644 --- a/packages/apm/test/span.test.ts +++ b/packages/apm/test/span.test.ts @@ -1,4 +1,5 @@ import { Hub, Scope } from '@sentry/hub'; +import { SpanStatus } from '@sentry/types'; import { Span, TRACEPARENT_REGEXP } from '../src'; @@ -51,25 +52,26 @@ describe('Span', () => { }); describe('status', () => { - test('setSuccess', () => { + test('setStatus', () => { const span = new Span({}); - span.setSuccess(); - expect(span.tags.status).toBe('success'); + span.setStatus(SpanStatus.PermissionDenied); + expect(span.tags.status).toBe('permission_denied'); }); - test('setFailure', () => { + test('setHttpStatus', () => { const span = new Span({}); - span.setFailure(); - expect(span.tags.status).toBe('failure'); + span.setHttpStatus(404); + expect(span.tags.status).toBe('not_found'); + expect(span.tags['http.status_code']).toBe('404'); }); test('isSuccess', () => { const span = new Span({}); - expect(span.isSuccess()).toBe(true); - span.setFailure(); expect(span.isSuccess()).toBe(false); - span.setSuccess(); + span.setHttpStatus(200); expect(span.isSuccess()).toBe(true); + span.setStatus(SpanStatus.PermissionDenied); + expect(span.isSuccess()).toBe(false); }); }); @@ -199,16 +201,16 @@ describe('Span', () => { test('should have success status extracted from tags', () => { const span = new Span({}); - span.setSuccess(); + span.setStatus(SpanStatus.Ok); const context = span.getTraceContext(); - expect((context as any).status).toBe('success'); + expect((context as any).status).toBe('ok'); }); test('should have failure status extracted from tags', () => { const span = new Span({}); - span.setFailure(); + span.setStatus(SpanStatus.ResourceExhausted); const context = span.getTraceContext(); - expect((context as any).status).toBe('failure'); + expect((context as any).status).toBe('resource_exhausted'); }); }); }); diff --git a/packages/apm/test/tslint.json b/packages/apm/test/tslint.json new file mode 100644 index 000000000000..0827b5c40259 --- /dev/null +++ b/packages/apm/test/tslint.json @@ -0,0 +1,6 @@ +{ + "extends": ["../tslint.json"], + "rules": { + "no-unsafe-any": false + } +} diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index cba7bd59dc08..5e89804f05a2 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -379,14 +379,14 @@ export class Hub implements HubInterface { } /** - * @inheritdoc + * @inheritDoc */ public startSpan(spanOrSpanContext?: Span | SpanContext, forceNoChild: boolean = false): Span { return this._callExtensionMethod('startSpan', spanOrSpanContext, forceNoChild); } /** - * @inheritdoc + * @inheritDoc */ public traceHeaders(): { [key: string]: string } { return this._callExtensionMethod<{ [key: string]: string }>('traceHeaders'); diff --git a/packages/node/package.json b/packages/node/package.json index 2c4601254b03..da80e331db90 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -28,9 +28,10 @@ }, "devDependencies": { "@types/cookie": "0.3.2", + "@types/express": "^4.17.2", "@types/lru-cache": "^5.1.0", "@types/node": "^11.13.7", - "express": "^4.16.4", + "express": "^4.17.1", "jest": "^24.7.1", "npm-run-all": "^4.1.2", "prettier": "^1.17.0", diff --git a/packages/node/src/handlers.ts b/packages/node/src/handlers.ts index 50294f60c896..0688a12e4557 100644 --- a/packages/node/src/handlers.ts +++ b/packages/node/src/handlers.ts @@ -40,11 +40,7 @@ export function tracingHandler(): ( scope.setSpan(transaction); }); res.once('finish', () => { - if (res.statusCode >= 500) { - transaction.setFailure(); - } else { - transaction.setSuccess(); - } + transaction.setHttpStatus(res.statusCode); transaction.finish(); }); diff --git a/packages/node/src/integrations/http.ts b/packages/node/src/integrations/http.ts index d3350e701e32..652d443c8356 100644 --- a/packages/node/src/integrations/http.ts +++ b/packages/node/src/integrations/http.ts @@ -80,9 +80,7 @@ function createHandlerWrapper( let span: Span; if (tracingEnabled) { - // TODO - const hub = getCurrentHub(); - span = hub.startSpan({ + span = getCurrentHub().startSpan({ description: `${typeof options === 'string' || !options.method ? 'GET' : options.method}|${requestUrl}`, op: 'request', }); @@ -94,9 +92,8 @@ function createHandlerWrapper( if (breadcrumbsEnabled) { addRequestBreadcrumb('response', requestUrl, this, res); } - // TODO: Mark >= 500 as failed as well? if (tracingEnabled && span) { - span.setSuccess(); + span.setHttpStatus(res.statusCode); span.finish(); } }) @@ -105,7 +102,7 @@ function createHandlerWrapper( addRequestBreadcrumb('error', requestUrl, this); } if (tracingEnabled && span) { - span.setFailure(); + span.setHttpStatus(500); span.finish(); } }); diff --git a/packages/node/src/version.ts b/packages/node/src/version.ts index f6b91c0c0ed6..a655144dad3c 100644 --- a/packages/node/src/version.ts +++ b/packages/node/src/version.ts @@ -1,2 +1,2 @@ -export const SDK_NAME = "sentry.javascript.node"; -export const SDK_VERSION = "5.9.0"; +export const SDK_NAME = 'sentry.javascript.node'; +export const SDK_VERSION = '5.9.0'; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 738782e52626..a45d86af566e 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -16,7 +16,7 @@ export { Response } from './response'; export { Scope } from './scope'; export { SdkInfo } from './sdkinfo'; export { Severity } from './severity'; -export { Span, SpanContext } from './span'; +export { Span, SpanContext, SpanStatus } from './span'; export { StackFrame } from './stackframe'; export { Stacktrace } from './stacktrace'; export { Status } from './status'; diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index 74f17fb6438f..903ada0515ea 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -24,23 +24,19 @@ export interface Span { setData(key: string, value: any): this; /** - * Sets the data attribute on the current span - * @param key Data key - * @param value Data value + * Sets the status attribute on the current span + * @param status http code used to set the status */ - setFailure(): this; + setStatus(status: SpanStatus): this; /** - * Sets the data attribute on the current span - * @param key Data key - * @param value Data value + * Sets the status attribute on the current span based on the http code + * @param httpStatus http code used to set the status */ - setSuccess(): this; + setHttpStatus(httpStatus: number): this; /** - * Sets the data attribute on the current span - * @param key Data key - * @param value Data value + * Determines whether span was successful (HTTP200) */ isSuccess(): boolean; } @@ -89,3 +85,91 @@ export interface SpanContext { */ data?: { [key: string]: any }; } + +/** The status of an Span. */ +export enum SpanStatus { + /** The operation completed successfully. */ + Ok = 'ok', + /** Deadline expired before operation could complete. */ + DealineExceeded = 'deadline_exceeded', + /** 401 Unauthorized (actually does mean unauthenticated according to RFC 7235) */ + Unauthenticated = 'unauthenticated', + /** 403 Forbidden */ + PermissionDenied = 'permission_denied', + /** 404 Not Found. Some requested entity (file or directory) was not found. */ + NotFound = 'not_found', + /** 429 Too Many Requests */ + ResourceExhausted = 'resource_exhausted', + /** Client specified an invalid argument. 4xx. */ + InvalidArgument = 'invalid_argument', + /** 501 Not Implemented */ + Unimplemented = 'unimplemented', + /** 503 Service Unavailable */ + Unavailable = 'unavailable', + /** Other/generic 5xx. */ + InternalError = 'internal_error', + /** Unknown. Any non-standard HTTP status code. */ + UnknownError = 'unknown_error', + /** The operation was cancelled (typically by the user). */ + Cancelled = 'cancelled', + /** Already exists (409) */ + AlreadyExists = 'already_exists', + /** Operation was rejected because the system is not in a state required for the operation's */ + FailedPrecondition = 'failed_precondition', + /** The operation was aborted, typically due to a concurrency issue. */ + Aborted = 'aborted', + /** Operation was attempted past the valid range. */ + OutOfRange = 'out_of_range', + /** Unrecoverable data loss or corruption */ + DataLoss = 'data_loss', +} + +// tslint:disable:no-unnecessary-qualifier no-namespace +export namespace SpanStatus { + /** + * Converts a HTTP status code into a {@link SpanStatus}. + * + * @param httpStatus The HTTP response status code. + * @returns The span status or {@link SpanStatus.UnknownError}. + */ + // tslint:disable-next-line:completed-docs + export function fromHttpCode(httpStatus: number): SpanStatus { + if (httpStatus < 400) { + return SpanStatus.Ok; + } + + if (httpStatus >= 400 && httpStatus < 500) { + switch (httpStatus) { + case 401: + return SpanStatus.Unauthenticated; + case 403: + return SpanStatus.PermissionDenied; + case 404: + return SpanStatus.NotFound; + case 409: + return SpanStatus.AlreadyExists; + case 413: + return SpanStatus.FailedPrecondition; + case 429: + return SpanStatus.ResourceExhausted; + default: + return SpanStatus.InvalidArgument; + } + } + + if (httpStatus >= 500 && httpStatus < 600) { + switch (httpStatus) { + case 501: + return SpanStatus.Unimplemented; + case 503: + return SpanStatus.Unavailable; + case 504: + return SpanStatus.DealineExceeded; + default: + return SpanStatus.InternalError; + } + } + + return SpanStatus.UnknownError; + } +} diff --git a/packages/utils/src/misc.ts b/packages/utils/src/misc.ts index 288103cee142..e61dba4a0d76 100644 --- a/packages/utils/src/misc.ts +++ b/packages/utils/src/misc.ts @@ -1,6 +1,6 @@ -import { Event, Integration, WrappedFunction } from "@sentry/types"; +import { Event, Integration, WrappedFunction } from '@sentry/types'; -import { isString } from "./is"; +import { isString } from './is'; /** Internal */ interface SentryGlobal { @@ -36,11 +36,7 @@ export function dynamicRequire(mod: any, request: string): any { */ export function isNodeEnv(): boolean { // tslint:disable:strict-type-predicates - return ( - Object.prototype.toString.call( - typeof process !== "undefined" ? process : 0 - ) === "[object process]" - ); + return Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]'; } const fallbackGlobalObject = {}; @@ -53,9 +49,9 @@ const fallbackGlobalObject = {}; export function getGlobalObject(): T & SentryGlobal { return (isNodeEnv() ? global - : typeof window !== "undefined" + : typeof window !== 'undefined' ? window - : typeof self !== "undefined" + : typeof self !== 'undefined' ? self : fallbackGlobalObject) as T & SentryGlobal; } @@ -98,22 +94,15 @@ export function uuid4(): string { }; return ( - pad(arr[0]) + - pad(arr[1]) + - pad(arr[2]) + - pad(arr[3]) + - pad(arr[4]) + - pad(arr[5]) + - pad(arr[6]) + - pad(arr[7]) + pad(arr[0]) + pad(arr[1]) + pad(arr[2]) + pad(arr[3]) + pad(arr[4]) + pad(arr[5]) + pad(arr[6]) + pad(arr[7]) ); } // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523 - return "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g, c => { + return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, c => { // tslint:disable-next-line:no-bitwise const r = (Math.random() * 16) | 0; // tslint:disable-next-line:no-bitwise - const v = c === "x" ? r : (r & 0x3) | 0x8; + const v = c === 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); } @@ -126,7 +115,7 @@ export function uuid4(): string { * @returns parsed URL object */ export function parseUrl( - url: string + url: string, ): { host?: string; path?: string; @@ -137,22 +126,20 @@ export function parseUrl( return {}; } - const match = url.match( - /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/ - ); + const match = url.match(/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/); if (!match) { return {}; } // coerce to undefined values to empty string so we don't get 'undefined' - const query = match[6] || ""; - const fragment = match[8] || ""; + const query = match[6] || ''; + const fragment = match[8] || ''; return { host: match[4], path: match[5], protocol: match[2], - relative: match[5] + query + fragment // everything minus origin + relative: match[5] + query + fragment, // everything minus origin }; } @@ -170,9 +157,9 @@ export function getEventDescription(event: Event): string { if (exception.type && exception.value) { return `${exception.type}: ${exception.value}`; } - return exception.type || exception.value || event.event_id || ""; + return exception.type || exception.value || event.event_id || ''; } - return event.event_id || ""; + return event.event_id || ''; } /** JSDoc */ @@ -183,9 +170,9 @@ interface ExtensibleConsole extends Console { /** JSDoc */ export function consoleSandbox(callback: () => any): any { const global = getGlobalObject(); - const levels = ["debug", "info", "warn", "error", "log", "assert"]; + const levels = ['debug', 'info', 'warn', 'error', 'log', 'assert']; - if (!("console" in global)) { + if (!('console' in global)) { return callback(); } @@ -194,16 +181,9 @@ export function consoleSandbox(callback: () => any): any { // Restore all wrapped console methods levels.forEach(level => { - if ( - level in global.console && - (originalConsole[level] as WrappedFunction).__sentry__ - ) { - wrappedLevels[level] = (originalConsole[ - level - ] as WrappedFunction).__sentry_wrapped__; - originalConsole[level] = (originalConsole[ - level - ] as WrappedFunction).__sentry_original__; + if (level in global.console && (originalConsole[level] as WrappedFunction).__sentry__) { + wrappedLevels[level] = (originalConsole[level] as WrappedFunction).__sentry_wrapped__; + originalConsole[level] = (originalConsole[level] as WrappedFunction).__sentry_original__; } }); @@ -225,18 +205,12 @@ export function consoleSandbox(callback: () => any): any { * @param type Type of the exception. * @hidden */ -export function addExceptionTypeValue( - event: Event, - value?: string, - type?: string -): void { +export function addExceptionTypeValue(event: Event, value?: string, type?: string): void { event.exception = event.exception || {}; event.exception.values = event.exception.values || []; event.exception.values[0] = event.exception.values[0] || {}; - event.exception.values[0].value = - event.exception.values[0].value || value || ""; - event.exception.values[0].type = - event.exception.values[0].type || type || "Error"; + event.exception.values[0].value = event.exception.values[0].value || value || ''; + event.exception.values[0].type = event.exception.values[0].type || type || 'Error'; } /** @@ -249,14 +223,13 @@ export function addExceptionMechanism( event: Event, mechanism: { [key: string]: any; - } = {} + } = {}, ): void { // TODO: Use real type with `keyof Mechanism` thingy and maybe make it better? try { // @ts-ignore // tslint:disable:no-non-null-assertion - event.exception!.values![0].mechanism = - event.exception!.values![0].mechanism || {}; + event.exception!.values![0].mechanism = event.exception!.values![0].mechanism || {}; Object.keys(mechanism).forEach(key => { // @ts-ignore event.exception!.values![0].mechanism[key] = mechanism[key]; @@ -273,7 +246,7 @@ export function getLocationHref(): string { try { return document.location.href; } catch (oO) { - return ""; + return ''; } } @@ -299,7 +272,7 @@ export function htmlTreeAsString(elem: unknown): string { const out = []; let height = 0; let len = 0; - const separator = " > "; + const separator = ' > '; const sepLength = separator.length; let nextStr; @@ -309,11 +282,7 @@ export function htmlTreeAsString(elem: unknown): string { // - nextStr is the 'html' element // - the length of the string that would be created exceeds MAX_OUTPUT_LEN // (ignore this limit if we are on the first iteration) - if ( - nextStr === "html" || - (height > 1 && - len + out.length * sepLength + nextStr.length >= MAX_OUTPUT_LEN) - ) { + if (nextStr === 'html' || (height > 1 && len + out.length * sepLength + nextStr.length >= MAX_OUTPUT_LEN)) { break; } @@ -325,7 +294,7 @@ export function htmlTreeAsString(elem: unknown): string { return out.reverse().join(separator); } catch (_oO) { - return ""; + return ''; } } @@ -350,7 +319,7 @@ function _htmlElementAsString(el: unknown): string { let i; if (!elem || !elem.tagName) { - return ""; + return ''; } out.push(elem.tagName.toLowerCase()); @@ -365,7 +334,7 @@ function _htmlElementAsString(el: unknown): string { out.push(`.${classes[i]}`); } } - const attrWhitelist = ["type", "name", "title", "alt"]; + const attrWhitelist = ['type', 'name', 'title', 'alt']; for (i = 0; i < attrWhitelist.length; i++) { key = attrWhitelist[i]; attr = elem.getAttribute(key); @@ -373,7 +342,7 @@ function _htmlElementAsString(el: unknown): string { out.push(`[${key}="${attr}"]`); } } - return out.join(""); + return out.join(''); } /** @@ -411,7 +380,7 @@ export function parseSemver(input: string): SemVer { major: isNaN(major) ? undefined : major, minor: isNaN(minor) ? undefined : minor, patch: isNaN(patch) ? undefined : patch, - prerelease: match[4] + prerelease: match[4], }; } @@ -422,10 +391,7 @@ const defaultRetryAfter = 60 * 1000; // 60 seconds * @param now current unix timestamp * @param header string representation of 'Retry-After' header */ -export function parseRetryAfterHeader( - now: number, - header?: string | number | null -): number { +export function parseRetryAfterHeader(now: number, header?: string | number | null): number { if (!header) { return defaultRetryAfter; } diff --git a/yarn.lock b/yarn.lock index 3eac15621d74..99b54b60a727 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1249,6 +1249,15 @@ "@types/express-serve-static-core" "*" "@types/serve-static" "*" +"@types/express@^4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.2.tgz#a0fb7a23d8855bac31bc01d5a58cadd9b2173e6c" + integrity sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "*" + "@types/serve-static" "*" + "@types/form-data@*": version "2.2.1" resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.2.1.tgz#ee2b3b8eaa11c0938289953606b745b738c54b1e" @@ -1607,6 +1616,14 @@ accepts@~1.3.4, accepts@~1.3.5: mime-types "~2.1.18" negotiator "0.6.1" +accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + acorn-dynamic-import@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948" @@ -1871,6 +1888,7 @@ array-find-index@^1.0.1: array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= array-from@^2.1.1: version "2.1.1" @@ -2622,7 +2640,23 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" -body-parser@1.18.3, body-parser@^1.16.1: +body-parser@1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +body-parser@^1.16.1: version "1.18.3" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" dependencies: @@ -2891,6 +2925,11 @@ bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + cacache@^11.0.1, cacache@^11.3.2: version "11.3.2" resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.2.tgz#2d81e308e3d258ca38125b676b98b2ac9ce69bfa" @@ -3459,9 +3498,12 @@ constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" -content-disposition@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" content-type@~1.0.4: version "1.0.4" @@ -3563,11 +3605,17 @@ convert-source-map@~1.1.0: cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= cookie@0.3.1, cookie@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + copy-concurrently@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" @@ -4514,38 +4562,39 @@ expect@^24.7.1: jest-message-util "^24.7.1" jest-regex-util "^24.3.0" -express@^4.16.4: - version "4.16.4" - resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" +express@^4.17.1: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== dependencies: - accepts "~1.3.5" + accepts "~1.3.7" array-flatten "1.1.1" - body-parser "1.18.3" - content-disposition "0.5.2" + body-parser "1.19.0" + content-disposition "0.5.3" content-type "~1.0.4" - cookie "0.3.1" + cookie "0.4.0" cookie-signature "1.0.6" debug "2.6.9" depd "~1.1.2" encodeurl "~1.0.2" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.1.1" + finalhandler "~1.1.2" fresh "0.5.2" merge-descriptors "1.0.1" methods "~1.1.2" on-finished "~2.3.0" - parseurl "~1.3.2" + parseurl "~1.3.3" path-to-regexp "0.1.7" - proxy-addr "~2.0.4" - qs "6.5.2" - range-parser "~1.2.0" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" safe-buffer "5.1.2" - send "0.16.2" - serve-static "1.13.2" - setprototypeof "1.1.0" - statuses "~1.4.0" - type-is "~1.6.16" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" utils-merge "1.0.1" vary "~1.1.2" @@ -4693,16 +4742,17 @@ finalhandler@1.1.0: statuses "~1.3.1" unpipe "~1.0.0" -finalhandler@1.1.1: - version "1.1.1" - resolved "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== dependencies: debug "2.6.9" encodeurl "~1.0.2" escape-html "~1.0.3" on-finished "~2.3.0" - parseurl "~1.3.2" - statuses "~1.4.0" + parseurl "~1.3.3" + statuses "~1.5.0" unpipe "~1.0.0" find-cache-dir@^2.0.0: @@ -4789,6 +4839,7 @@ formatio@1.1.1: forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= fragment-cache@^0.2.1: version "0.2.1" @@ -4805,6 +4856,7 @@ fresh@0.5.0: fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= from2@^2.1.0: version "2.3.0" @@ -5443,7 +5495,7 @@ http-cache-semantics@^3.8.1: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== -http-errors@1.6.3, http-errors@~1.6.1, http-errors@~1.6.2, http-errors@~1.6.3: +http-errors@1.6.3, http-errors@~1.6.1, http-errors@~1.6.3: version "1.6.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= @@ -5453,6 +5505,28 @@ http-errors@1.6.3, http-errors@~1.6.1, http-errors@~1.6.2, http-errors@~1.6.3: setprototypeof "1.1.0" statuses ">= 1.4.0 < 2" +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + http-proxy-agent@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" @@ -5614,6 +5688,11 @@ inherits@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" +inherits@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + ini@^1.3.2, ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" @@ -5689,9 +5768,10 @@ ip@1.1.5, ip@^1.1.5: resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= -ipaddr.js@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" +ipaddr.js@1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" + integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== is-accessor-descriptor@^0.1.6: version "0.1.6" @@ -7427,6 +7507,7 @@ meow@^4.0.0: merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= merge-stream@^1.0.1: version "1.0.1" @@ -7443,6 +7524,7 @@ merge2@^1.2.3: methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= micro-compress@1.0.0: version "1.0.0" @@ -7497,6 +7579,11 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" +mime-db@1.42.0: + version "1.42.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.42.0.tgz#3e252907b4c7adb906597b4b65636272cf9e7bac" + integrity sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ== + "mime-db@>= 1.36.0 < 2", mime-db@~1.37.0: version "1.37.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" @@ -7531,14 +7618,22 @@ mime-types@^2.1.12, mime-types@~2.1.19: dependencies: mime-db "~1.38.0" +mime-types@~2.1.24: + version "2.1.25" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.25.tgz#39772d46621f93e2a80a856c53b86a62156a6437" + integrity sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg== + dependencies: + mime-db "1.42.0" + mime@1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" integrity sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM= -mime@1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== mime@^2.2.0, mime@^2.3.1: version "2.4.0" @@ -7764,6 +7859,11 @@ negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + neo-async@^2.5.0: version "2.6.0" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" @@ -8514,6 +8614,11 @@ parseurl@~1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" @@ -8567,6 +8672,7 @@ path-parse@^1.0.5, path-parse@^1.0.6: path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= path-to-regexp@^1.7.0: version "1.7.0" @@ -8803,12 +8909,13 @@ protoduck@^5.0.1: dependencies: genfun "^5.0.0" -proxy-addr@~2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" +proxy-addr@~2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" + integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== dependencies: forwarded "~0.1.2" - ipaddr.js "1.8.0" + ipaddr.js "1.9.0" prr@~1.0.1: version "1.0.1" @@ -8893,6 +9000,11 @@ qs@6.5.2, qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + querystring-es3@^0.2.0, querystring-es3@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -8923,6 +9035,11 @@ range-parser@^1.2.0, range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + raw-body@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" @@ -8941,6 +9058,16 @@ raw-body@2.3.3: iconv-lite "0.4.23" unpipe "1.0.0" +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -9614,9 +9741,10 @@ send@0.15.3: range-parser "~1.2.0" statuses "~1.3.1" -send@0.16.2: - version "0.16.2" - resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== dependencies: debug "2.6.9" depd "~1.1.2" @@ -9625,12 +9753,12 @@ send@0.16.2: escape-html "~1.0.3" etag "~1.8.1" fresh "0.5.2" - http-errors "~1.6.2" - mime "1.4.1" - ms "2.0.0" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" on-finished "~2.3.0" - range-parser "~1.2.0" - statuses "~1.4.0" + range-parser "~1.2.1" + statuses "~1.5.0" serialize-javascript@^1.4.0: version "1.5.0" @@ -9641,14 +9769,15 @@ serialize-javascript@^1.6.1: resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.6.1.tgz#4d1f697ec49429a847ca6f442a2a755126c4d879" integrity sha512-A5MOagrPFga4YaKQSWHryl7AXvbQkEqpw4NNYMTNYUNV51bA8ABHgYFpqKx+YFFrw59xMV1qGH1R4AgoNIVgCw== -serve-static@1.13.2: - version "1.13.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== dependencies: encodeurl "~1.0.2" escape-html "~1.0.3" - parseurl "~1.3.2" - send "0.16.2" + parseurl "~1.3.3" + send "0.17.1" serve@^5.1.5: version "5.2.4" @@ -9709,6 +9838,11 @@ setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + sha.js@^2.4.0, sha.js@^2.4.8: version "2.4.11" resolved "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" @@ -10078,7 +10212,7 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -"statuses@>= 1.4.0 < 2": +"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -10086,10 +10220,6 @@ statuses@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" -statuses@~1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" - stealthy-require@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" @@ -10562,6 +10692,11 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" @@ -10708,6 +10843,14 @@ type-is@~1.6.16: media-typer "0.3.0" mime-types "~2.1.18" +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" From ea23290feb08c0205c8b82b24d58a37a562467f3 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 27 Nov 2019 10:33:35 +0100 Subject: [PATCH 59/63] feat: Move instrumentation and dsn to utils --- packages/apm/src/integrations/index.ts | 2 +- packages/apm/src/integrations/tracing.ts | 50 +++++++++++-------- packages/browser/src/index.ts | 1 - .../browser/src/integrations/breadcrumbs.ts | 2 +- packages/core/src/api.ts | 4 +- packages/core/src/baseclient.ts | 3 +- packages/core/src/index.ts | 1 - packages/node/src/backend.ts | 3 +- packages/{core => utils}/src/dsn.ts | 2 +- packages/utils/src/index.ts | 2 + packages/{browser => utils}/src/instrument.ts | 30 ++++------- 11 files changed, 46 insertions(+), 54 deletions(-) rename packages/{core => utils}/src/dsn.ts (98%) rename packages/{browser => utils}/src/instrument.ts (95%) diff --git a/packages/apm/src/integrations/index.ts b/packages/apm/src/integrations/index.ts index 3c10eab68153..8833c8cd301c 100644 --- a/packages/apm/src/integrations/index.ts +++ b/packages/apm/src/integrations/index.ts @@ -1,2 +1,2 @@ export { Express } from './express'; -export { Tracing, TracingHandlers } from './tracing'; +export { Tracing } from './tracing'; diff --git a/packages/apm/src/integrations/tracing.ts b/packages/apm/src/integrations/tracing.ts index d6fc2eb352b6..185c3caaf56e 100644 --- a/packages/apm/src/integrations/tracing.ts +++ b/packages/apm/src/integrations/tracing.ts @@ -1,5 +1,12 @@ import { EventProcessor, Hub, Integration, Span, SpanContext } from '@sentry/types'; -import { fill, getGlobalObject, isMatchingPattern, logger, supportsNativeFetch } from '@sentry/utils'; +import { + addInstrumentationHandler, + fill, + getGlobalObject, + isMatchingPattern, + logger, + supportsNativeFetch, +} from '@sentry/utils'; /** JSDoc */ interface TracingOptions { @@ -111,13 +118,29 @@ export class Tracing implements Integration { // tslint:disable-next-line: no-non-null-assertion if (this._options!.traceXHR !== false) { + addInstrumentationHandler({ + callback: xhrCallback, + type: 'xhr', + }); this._traceXHR(getCurrentHub); } // tslint:disable-next-line: no-non-null-assertion if (this._options!.traceFetch !== false) { + addInstrumentationHandler({ + callback: fetchCallback, + type: 'fetch', + }); this._traceFetch(getCurrentHub); } + // tslint:disable-next-line: no-non-null-assertion + if (this._options!.startTransactionOnLocationChange) { + addInstrumentationHandler({ + callback: historyCallback, + type: 'history', + }); + } + if (global.location && global.location.href) { // `${global.location.href}` will be used a temp transaction name Tracing.startIdleTransaction(global.location.href, { @@ -419,13 +442,14 @@ function xhrCallback(handlerData: { [key: string]: any }): void { if (!Tracing.options.shouldCreateSpanForRequest(xhr.url)) { return; } - + console.log(handlerData.xhr); // We only capture complete, non-sentry requests if (handlerData.xhr.__sentry_own_request__) { return; } - if (handlerData.requestComplete && handlerData.xhr.__sentry_xhr_activity_id__) { + console.log(handlerData, handlerData.__sentry_own_request__); + if (handlerData.endTimestamp && handlerData.xhr.__sentry_xhr_activity_id__) { Tracing.popActivity(handlerData.xhr.__sentry_xhr_activity_id__, handlerData.xhr.__sentry_xhr__); return; } @@ -450,7 +474,7 @@ function fetchCallback(handlerData: { [key: string]: any }): void { return; } - if (handlerData.requestComplete && handlerData.__activity) { + if (handlerData.endTimestamp && handlerData.__activity) { Tracing.popActivity(handlerData.__activity, handlerData.fetchData); } else { handlerData.__activity = Tracing.pushActivity('fetch', { @@ -480,21 +504,3 @@ function historyCallback(_: { [key: string]: any }): void { }); } } - -const historyHandler = { - callback: historyCallback, - type: 'history', -}; - -const xhrHandler = { - callback: xhrCallback, - type: 'xhr', -}; - -const fetchHandler = { - callback: fetchCallback, - type: 'fetch', -}; - -// tslint:disable-next-line: variable-name -export const TracingHandlers = [historyHandler, xhrHandler, fetchHandler]; diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index e999ad0d247f..af6df17741a7 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -37,7 +37,6 @@ export { BrowserOptions } from './backend'; export { BrowserClient, ReportDialogOptions } from './client'; export { defaultIntegrations, forceLoad, init, lastEventId, onLoad, showReportDialog, flush, close, wrap } from './sdk'; export { SDK_NAME, SDK_VERSION } from './version'; -export { addInstrumentationHandler } from './instrument'; import { Integrations as CoreIntegrations } from '@sentry/core'; import { getGlobalObject } from '@sentry/utils'; diff --git a/packages/browser/src/integrations/breadcrumbs.ts b/packages/browser/src/integrations/breadcrumbs.ts index 0f0b118d7cb6..fa7886d9e9fb 100644 --- a/packages/browser/src/integrations/breadcrumbs.ts +++ b/packages/browser/src/integrations/breadcrumbs.ts @@ -1,6 +1,7 @@ import { API, getCurrentHub } from '@sentry/core'; import { Integration, Severity } from '@sentry/types'; import { + addInstrumentationHandler, getEventDescription, getGlobalObject, htmlTreeAsString, @@ -11,7 +12,6 @@ import { } from '@sentry/utils'; import { BrowserClient } from '../client'; -import { addInstrumentationHandler } from '../instrument'; /** * @hidden diff --git a/packages/core/src/api.ts b/packages/core/src/api.ts index 2867de307c7e..5198e887dc69 100644 --- a/packages/core/src/api.ts +++ b/packages/core/src/api.ts @@ -1,7 +1,5 @@ import { DsnLike } from '@sentry/types'; -import { timestampWithMs, urlEncode } from '@sentry/utils'; - -import { Dsn } from './dsn'; +import { Dsn, timestampWithMs, urlEncode } from '@sentry/utils'; const SENTRY_API_VERSION = '7'; diff --git a/packages/core/src/baseclient.ts b/packages/core/src/baseclient.ts index 841a2037a29c..51ed8a0d74a7 100644 --- a/packages/core/src/baseclient.ts +++ b/packages/core/src/baseclient.ts @@ -1,9 +1,8 @@ import { Scope } from '@sentry/hub'; import { Client, Event, EventHint, Integration, IntegrationClass, Options, SdkInfo, Severity } from '@sentry/types'; -import { isPrimitive, isThenable, logger, SyncPromise, truncate, uuid4 } from '@sentry/utils'; +import { Dsn, isPrimitive, isThenable, logger, SyncPromise, truncate, uuid4 } from '@sentry/utils'; import { Backend, BackendClass } from './basebackend'; -import { Dsn } from './dsn'; import { IntegrationIndex, setupIntegrations } from './integration'; /** diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index ad7e542cbd66..fce6345cf635 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -16,7 +16,6 @@ export { addGlobalEventProcessor, getCurrentHub, getHubFromCarrier, Hub, Scope } export { API } from './api'; export { BaseClient } from './baseclient'; export { BackendClass, BaseBackend } from './basebackend'; -export { Dsn } from './dsn'; export { initAndBind, ClientClass } from './sdk'; export { NoopTransport } from './transports/noop'; diff --git a/packages/node/src/backend.ts b/packages/node/src/backend.ts index 8b1d6c53241f..34a2a86b0dca 100644 --- a/packages/node/src/backend.ts +++ b/packages/node/src/backend.ts @@ -1,8 +1,9 @@ -import { BaseBackend, Dsn, getCurrentHub } from '@sentry/core'; +import { BaseBackend, getCurrentHub } from '@sentry/core'; import { Event, EventHint, Mechanism, Options, Severity, Transport, TransportOptions } from '@sentry/types'; import { addExceptionMechanism, addExceptionTypeValue, + Dsn, extractExceptionKeysForMessage, isError, isPlainObject, diff --git a/packages/core/src/dsn.ts b/packages/utils/src/dsn.ts similarity index 98% rename from packages/core/src/dsn.ts rename to packages/utils/src/dsn.ts index 998c19a23aba..8ce224dcfe24 100644 --- a/packages/core/src/dsn.ts +++ b/packages/utils/src/dsn.ts @@ -1,5 +1,5 @@ import { DsnComponents, DsnLike, DsnProtocol } from '@sentry/types'; -import { SentryError } from '@sentry/utils'; +import { SentryError } from './error'; /** Regular expression used to parse a Dsn. */ const DSN_REGEX = /^(?:(\w+):)\/\/(?:(\w+)(?::(\w+))?@)([\w\.-]+)(?::(\d+))?\/(.+)/; diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 8dc96c9986b8..6457c22d419b 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -10,3 +10,5 @@ export * from './promisebuffer'; export * from './string'; export * from './supports'; export * from './syncpromise'; +export * from './instrument'; +export * from './dsn'; diff --git a/packages/browser/src/instrument.ts b/packages/utils/src/instrument.ts similarity index 95% rename from packages/browser/src/instrument.ts rename to packages/utils/src/instrument.ts index a5365b27ea0c..2eac92faf5e4 100644 --- a/packages/browser/src/instrument.ts +++ b/packages/utils/src/instrument.ts @@ -1,18 +1,12 @@ /* tslint:disable:only-arrow-functions no-unsafe-any */ -import { API, getCurrentHub } from '@sentry/core'; import { WrappedFunction } from '@sentry/types'; -import { - fill, - getFunctionName, - getGlobalObject, - isString, - logger, - supportsHistory, - supportsNativeFetch, -} from '@sentry/utils'; - -import { BrowserClient } from './client'; + +import { logger } from './logger'; +import { getFunctionName, getGlobalObject } from './misc'; +import { fill } from './object'; +import { isString } from './is'; +import { supportsHistory, supportsNativeFetch } from './supports'; const global = getGlobalObject(); @@ -214,15 +208,9 @@ function instrumentXHR(): void { url: args[1], }; - const client = getCurrentHub().getClient(); - const dsn = client && client.getDsn(); - if (dsn) { - const filterUrl = new API(dsn).getStoreEndpoint(); - // if Sentry key appears in URL, don't capture it as a request - // but rather as our own 'sentry' type breadcrumb - if (isString(url) && (filterUrl && url.indexOf(filterUrl) !== -1)) { - this.__sentry_own_request__ = true; - } + // if Sentry key appears in URL, don't capture it as a request + if (isString(url) && this.__sentry_xhr__.method === 'POST' && url.match(/sentry_key/)) { + this.__sentry_own_request__ = true; } return originalOpen.apply(this, args); From e4d605d52d9ffc134b73e2382972a48508800efc Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 27 Nov 2019 11:43:45 +0100 Subject: [PATCH 60/63] feat: Auto status code, Fix idle navigation transaction --- packages/apm/src/integrations/tracing.ts | 30 +++++++++++++++--------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/packages/apm/src/integrations/tracing.ts b/packages/apm/src/integrations/tracing.ts index 185c3caaf56e..88f8fbfe0801 100644 --- a/packages/apm/src/integrations/tracing.ts +++ b/packages/apm/src/integrations/tracing.ts @@ -1,4 +1,4 @@ -import { EventProcessor, Hub, Integration, Span, SpanContext } from '@sentry/types'; +import { EventProcessor, Hub, Integration, Span, SpanContext, SpanStatus } from '@sentry/types'; import { addInstrumentationHandler, fill, @@ -289,14 +289,10 @@ export class Tracing implements Integration { return undefined; } - const activeTransaction = Tracing._activeTransaction; - - if (activeTransaction) { - // If we already have an active transaction it means one of two things - // a) The user did rapid navigation changes and didn't wait until the transaction was finished - // b) A activity wasn't popped correctly and therefore the transaction is stalling - activeTransaction.finish(); - } + // If we already have an active transaction it means one of two things + // a) The user did rapid navigation changes and didn't wait until the transaction was finished + // b) A activity wasn't popped correctly and therefore the transaction is stalling + Tracing.finishIdleTransaction(); const _getCurrentHub = Tracing._getCurrentHub; if (!_getCurrentHub) { @@ -357,6 +353,16 @@ export class Tracing implements Integration { } } + /** + * Sets the status of the current active transaction (if there is one) + */ + public static setTransactionStatus(status: SpanStatus): void { + const active = Tracing._activeTransaction; + if (active) { + active.setStatus(status); + } + } + /** * Starts tracking for a specifc activity */ @@ -403,6 +409,9 @@ export class Tracing implements Integration { if (spanData) { Object.keys(spanData).forEach((key: string) => { span.setData(key, spanData[key]); + if (key === 'status_code') { + span.setHttpStatus(spanData[key] as number); + } }); } span.finish(); @@ -442,13 +451,12 @@ function xhrCallback(handlerData: { [key: string]: any }): void { if (!Tracing.options.shouldCreateSpanForRequest(xhr.url)) { return; } - console.log(handlerData.xhr); + // We only capture complete, non-sentry requests if (handlerData.xhr.__sentry_own_request__) { return; } - console.log(handlerData, handlerData.__sentry_own_request__); if (handlerData.endTimestamp && handlerData.xhr.__sentry_xhr_activity_id__) { Tracing.popActivity(handlerData.xhr.__sentry_xhr_activity_id__, handlerData.xhr.__sentry_xhr__); return; From 9cc5548461c5c2c8326362a8ca1337936cb5dc84 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 27 Nov 2019 11:56:23 +0100 Subject: [PATCH 61/63] feat: Readme, lint, changelog --- CHANGELOG.md | 2 ++ packages/apm/README.md | 11 ++++------- packages/core/test/lib/api.test.ts | 3 ++- packages/utils/src/dsn.ts | 1 + packages/utils/src/instrument.ts | 2 +- packages/utils/src/supports.ts | 3 ++- packages/{core/test/lib => utils/test}/dsn.test.ts | 5 ++--- 7 files changed, 14 insertions(+), 13 deletions(-) rename packages/{core/test/lib => utils/test}/dsn.test.ts (98%) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce92bb9d361a..25fe05060d5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ - [hub] feat: Add more span functions (#2161) - [integrations] feat: Change `Tracing` integration (#2161) - [browser] feat: Refactor breadcrumbs integration to allow for custom handlers +- [utils] feat: Move insturment to utils +- [apm] feat: Add `@sentry/apm` package ## 5.9.1 diff --git a/packages/apm/README.md b/packages/apm/README.md index 4d54c4d983f5..cd1f12fd0f77 100644 --- a/packages/apm/README.md +++ b/packages/apm/README.md @@ -9,9 +9,9 @@ # TODO -[![npm version](https://img.shields.io/npm/v/@sentry/core.svg)](https://www.npmjs.com/package/@sentry/core) -[![npm dm](https://img.shields.io/npm/dm/@sentry/core.svg)](https://www.npmjs.com/package/@sentry/core) -[![npm dt](https://img.shields.io/npm/dt/@sentry/core.svg)](https://www.npmjs.com/package/@sentry/core) +[![npm version](https://img.shields.io/npm/v/@sentry/apm.svg)](https://www.npmjs.com/package/@sentry/apm) +[![npm dm](https://img.shields.io/npm/dm/@sentry/apm.svg)](https://www.npmjs.com/package/@sentry/apm) +[![npm dt](https://img.shields.io/npm/dt/@sentry/apm.svg)](https://www.npmjs.com/package/@sentry/apm) [![typedoc](https://img.shields.io/badge/docs-typedoc-blue.svg)](http://getsentry.github.io/sentry-javascript/) ## Links @@ -21,7 +21,4 @@ ## General -This package contains interface definitions, base classes and utilities for building Sentry JavaScript SDKs, like -`@sentry/node` or `@sentry/browser`. - -Please consider all classes and exported functions and interfaces `internal`. +This package contains extensions to the `@sentry/hub` to enable APM related functionality. It also provides integrations for Browser and Node that provide a good experience out of the box. diff --git a/packages/core/test/lib/api.test.ts b/packages/core/test/lib/api.test.ts index 2bc914cc720a..99641c55b656 100644 --- a/packages/core/test/lib/api.test.ts +++ b/packages/core/test/lib/api.test.ts @@ -1,5 +1,6 @@ +import { Dsn } from '@sentry/utils'; + import { API } from '../../src/api'; -import { Dsn } from '../../src/dsn'; const dsnPublic = 'https://abc@sentry.io:1234/subpath/123'; const legacyDsn = 'https://abc:123@sentry.io:1234/subpath/123'; diff --git a/packages/utils/src/dsn.ts b/packages/utils/src/dsn.ts index 8ce224dcfe24..29807dd68d67 100644 --- a/packages/utils/src/dsn.ts +++ b/packages/utils/src/dsn.ts @@ -1,4 +1,5 @@ import { DsnComponents, DsnLike, DsnProtocol } from '@sentry/types'; + import { SentryError } from './error'; /** Regular expression used to parse a Dsn. */ diff --git a/packages/utils/src/instrument.ts b/packages/utils/src/instrument.ts index 2eac92faf5e4..24fcbb724199 100644 --- a/packages/utils/src/instrument.ts +++ b/packages/utils/src/instrument.ts @@ -2,10 +2,10 @@ import { WrappedFunction } from '@sentry/types'; +import { isString } from './is'; import { logger } from './logger'; import { getFunctionName, getGlobalObject } from './misc'; import { fill } from './object'; -import { isString } from './is'; import { supportsHistory, supportsNativeFetch } from './supports'; const global = getGlobalObject(); diff --git a/packages/utils/src/supports.ts b/packages/utils/src/supports.ts index a52624fefae2..b98bd40a7767 100644 --- a/packages/utils/src/supports.ts +++ b/packages/utils/src/supports.ts @@ -83,7 +83,6 @@ function isNativeFetch(func: Function): boolean { return func && /^function fetch\(\)\s+\{\s+\[native code\]\s+\}$/.test(func.toString()); } - /** * Tells whether current environment supports Fetch API natively * {@link supportsNativeFetch}. @@ -98,6 +97,7 @@ export function supportsNativeFetch(): boolean { const global = getGlobalObject(); // Fast path to avoid DOM I/O + // tslint:disable-next-line:no-unbound-method if (isNativeFetch(global.fetch)) { return true; } @@ -112,6 +112,7 @@ export function supportsNativeFetch(): boolean { try { doc.head.appendChild(sandbox); if (sandbox.contentWindow && sandbox.contentWindow.fetch) { + // tslint:disable-next-line:no-unbound-method result = isNativeFetch(sandbox.contentWindow.fetch); } doc.head.removeChild(sandbox); diff --git a/packages/core/test/lib/dsn.test.ts b/packages/utils/test/dsn.test.ts similarity index 98% rename from packages/core/test/lib/dsn.test.ts rename to packages/utils/test/dsn.test.ts index 45678efb1ea9..840e95ebde4b 100644 --- a/packages/core/test/lib/dsn.test.ts +++ b/packages/utils/test/dsn.test.ts @@ -1,6 +1,5 @@ -import { SentryError } from '@sentry/utils'; - -import { Dsn } from '../../src/dsn'; +import { Dsn } from '../src/dsn'; +import { SentryError } from '../src/error'; describe('Dsn', () => { describe('fromComponents', () => { From 7d5d3f258c9d84686dc8f0644b0df3898ada2a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Mon, 2 Dec 2019 14:39:42 +0100 Subject: [PATCH 62/63] fix: Dont clash between span and scope trace context data --- packages/apm/src/span.ts | 12 +++--------- packages/hub/src/scope.ts | 2 +- packages/types/src/span.ts | 2 +- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/packages/apm/src/span.ts b/packages/apm/src/span.ts index c4f045e46fc2..7a16c00442e4 100644 --- a/packages/apm/src/span.ts +++ b/packages/apm/src/span.ts @@ -287,7 +287,6 @@ export class Span implements SpanInterface, SpanContext { } return this._hub.captureEvent({ - contexts: { trace: this.getTraceContext() }, spans: finishedSpans, start_timestamp: this.startTimestamp, tags: this.tags, @@ -312,22 +311,17 @@ export class Span implements SpanInterface, SpanContext { * @inheritDoc */ public getTraceContext(): object { - const context = { + return { data: this.data, description: this.description, op: this.op, parent_span_id: this._parentSpanId, span_id: this._spanId, + // Undefined status will be dropped by `JSON.stringify` anyway so it's safe to read it directly like that + status: this.tags.status, tags: this.tags, trace_id: this._traceId, }; - - if (this.tags.status) { - // TODO: Fixme, just use better typings - (context as any).status = this.tags.status; - } - - return context; } /** diff --git a/packages/hub/src/scope.ts b/packages/hub/src/scope.ts index 97a3c24500c3..fd3cd6ef331f 100644 --- a/packages/hub/src/scope.ts +++ b/packages/hub/src/scope.ts @@ -329,7 +329,7 @@ export class Scope implements ScopeInterface { } if (this._span) { event.contexts = event.contexts || {}; - event.contexts.trace = this._span; + event.contexts.trace = this._span.getTraceContext(); } this._applyFingerprint(event); diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index 903ada0515ea..0c7a9383b1da 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -54,7 +54,7 @@ export interface SpanContext { /** * Completion status of the Span. */ - status?: boolean; + status?: SpanStatus; /** * Parent Span ID */ From 073920fe3216bb3271ec83e2a6a4670a269498a3 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Mon, 2 Dec 2019 16:07:03 +0100 Subject: [PATCH 63/63] meta: Docs for options --- packages/apm/src/integrations/tracing.ts | 40 +++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/packages/apm/src/integrations/tracing.ts b/packages/apm/src/integrations/tracing.ts index 88f8fbfe0801..bae0badc9f23 100644 --- a/packages/apm/src/integrations/tracing.ts +++ b/packages/apm/src/integrations/tracing.ts @@ -8,10 +8,28 @@ import { supportsNativeFetch, } from '@sentry/utils'; -/** JSDoc */ +/** + * Options for Tracing integration + */ interface TracingOptions { + /** + * List of strings / regex where the integration should create Spans out of. Additionally this will be used + * to define which outgoing requests the `sentry-trace` header will be attached to. + * + * Default: ['localhost', /^\//] + */ tracingOrigins: Array; + /** + * Flag to disable patching all together for fetch requests. + * + * Default: true + */ traceFetch: boolean; + /** + * Flag to disable patching all together for xhr requests. + * + * Default: true + */ traceXHR: boolean; /** * This function will be called before creating a span for a request with the given url. @@ -20,8 +38,28 @@ interface TracingOptions { * By default it uses the `tracingOrigins` options as a url match. */ shouldCreateSpanForRequest(url: string): boolean; + /** + * The time to wait in ms until the transaction will be finished. The transaction will use the end timestamp of + * the last finished span as the endtime for the transaction. + * + * Default: 500 + */ idleTimeout: number; + /** + * Flag to enable/disable creation of `navigation` transaction on history changes. Useful for react applications with + * a router. + * + * Default: true + */ startTransactionOnLocationChange: boolean; + /** + * Sample to determine if the Integration should instrument anything. The decision will be taken once per load + * on initalization. + * 0 = 0% chance of instrumenting + * 1 = 100% change of instrumenting + * + * Default: 1 + */ tracesSampleRate: number; }