Compare commits

...

35 Commits

Author SHA1 Message Date
rozetko 67ac4e073f 2.0.4 1 year ago
rozetko 813c50d36d fix grafana errors not caught by tsdb-kit 1 year ago
rozetko b771a81962 Merge pull request 'SQL: support Grafana aggregation macros' (#13) from sql-support-grafana-aggregation-macros into master 1 year ago
rozetko 32425542ae 2.0.3 1 year ago
rozetko 3c768d4d92 tests for Grafana SQL aggregation macros 1 year ago
rozetko 7a01a86ddb SQL: support Grafana aggregation macros ($__timeGroup and $__timeGroupAlias) 1 year ago
rozetko ad6b77b89d 2.0.2 1 year ago
rozetko 3ca05e5ca2 Merge branch 'master' of code.corpglory.net:hastic/tsdb-kit 1 year ago
rozetko f0b7fc9b61 2.0.1 1 year ago
rozetko f8367d9e58 Merge pull request 'SQL: support Grafana 9' (#12) from update-sql-exporter-to-work-with-grafana-9 into master 1 year ago
rozetko 6bf90e69bb upd SQL test 1 year ago
rozetko 7c89c455ed update SQL connector to support Grafana 9 1 year ago
rozetko f6679a98be Merge pull request 'CLI-arguments && docs && Prometheus auth' (#8) from cli-arguments into master 2 years ago
rozetko fe51c32f2a 2.0.0 2 years ago
rozetko 4b38cbdb34 Prometheus: support auth 2 years ago
rozetko eac608eab8 upd readme 2 years ago
rozetko 864537766d version from package.json 2 years ago
rozetko afcf696ae5 new `dev` scripts 2 years ago
rozetko 7b487f9fbb 1.2.0-beta2 2 years ago
rozetko 8629f86332 shabang to bin 2 years ago
rozetko 6448f52095 upd npmignore 2 years ago
rozetko 5212d7a89a 1.2.0-beta 2 years ago
rozetko d68faaa8ec upd readme 2 years ago
rozetko 82dfc20b2f init CLI arguments 2 years ago
rozetko e38c2db4e6 Merge pull request 'QueryService refactoring' (#6) from query-service-refactoring into master 2 years ago
rozetko fb3b597b3f QueryService refactoring: 2 years ago
rozetko bc6988b31b Merge pull request 'better names' (#5) from better-names into master 2 years ago
rozetko 087e001534 rename files 2 years ago
rozetko 5e20b4de96 better names 2 years ago
rozetko 8112975b12 Merge pull request 'direct Prometheus queries' (#1) from direct-prometheus-queries into master 2 years ago
rozetko b8f1f27f1a some refactoring 2 years ago
rozetko de97390d1e sample bin file 2 years ago
rozetko fbf6c4949f upd types 2 years ago
rozetko 61562a9c94 fix bin build 2 years ago
rozetko 3889b3dd64 rm package-lock 2 years ago
  1. 9
      .npmignore
  2. 32
      README.md
  3. 8
      bin.tsconfig.json
  4. 6
      lib.tsconfig.json
  5. 5124
      package-lock.json
  6. 19
      package.json
  7. 13
      spec/elasticsearch.jest.ts
  8. 10
      spec/graphite.jest.ts
  9. 17
      spec/influxdb.jest.ts
  10. 20
      spec/prometheus.jest.ts
  11. 125
      spec/sql.jest.ts
  12. 2
      spec/utils.jest.ts
  13. 31
      src/connectors/connector_factory.ts
  14. 44
      src/connectors/elasticsearch.ts
  15. 12
      src/connectors/graphite.ts
  16. 58
      src/connectors/index.ts
  17. 13
      src/connectors/influxdb.ts
  18. 5
      src/connectors/mysql.ts
  19. 5
      src/connectors/postgres.ts
  20. 28
      src/connectors/prometheus.ts
  21. 31
      src/connectors/sql.ts
  22. 8
      src/connectors/utils.ts
  23. 134
      src/grafana_service.ts
  24. 58
      src/index.ts
  25. 40
      src/metrics/metric.ts
  26. 78
      src/metrics/metrics_factory.ts
  27. 5
      src/metrics/mysql_metric.ts
  28. 5
      src/metrics/postgres_metric.ts
  29. 62
      src/models/query_config.ts
  30. 11
      src/services/query_service/base.ts
  31. 52
      src/services/query_service/direct.ts
  32. 64
      src/services/query_service/grafana.ts
  33. 23
      src/services/query_service/query_service_factory.ts
  34. 50
      src/tsdb-kit/index.ts
  35. 15
      src/types.ts
  36. 33
      webpack.config.js
  37. 650
      yarn.lock

9
.npmignore

@ -2,7 +2,8 @@ src
spec
.travis.yml
jest.config.js
tsconfig.lib.json
tsconfig.bin.json
tsconfig.jest.json
lib.tsconfig.json
bin.tsconfig.json
webpack.config.js
yarn.lock
.vscode

32
README.md

@ -1,21 +1,43 @@
# tsdb-kit
[![Build Status](https://travis-ci.org/CorpGlory/tsdb-kit.svg?branch=master)](https://travis-ci.org/CorpGlory/tsdb-kit)
TSDB-kit is a node.js library and CLI-tool for querying timeseries-datasources.
Node.js library and utilities for running Grafana datasources on backend.
You can send your datasource metrics from Grafana to compile it on Node.js and query your datasource via Grafana API in background.
## Features
User gets a unified interface to all datasources. Library gives single output format: fields order, time units, etc
- can query datasources directly or using Grafana as proxy
- can be used as a lib from your node.js-code or as a CLI-tool
- user gets a unified interface to all datasources. Library gives single output format: fields order, time units, etc.
## Supported datasources
### Direct
* Prometheus
### Grafana
* Influxdb
* Graphite
* Prometheus
* PostgreSQL / TimescaleDB / MySQL
* ElasticSearch
Please write us at ping@corpglory.com if you want your datasource to be supported:
Please write us at ping@corpglory.com if you want your datasource to be supported
## Usage
### Lib (TODO)
### CLI
For now, CLI supports only direct Prometheus queries
For example:
`npx @corpglory/tsdb-kit -U http://localhost:9090 -q '100-(avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)' -u my_user -p my_password`
## Development (TODO)
## Projects based on library
* [grafana-data-exporter](https://github.com/CorpGlory/grafana-data-exporter)

8
bin.tsconfig.json

@ -1,10 +1,10 @@
{
"compilerOptions": {
"moduleResolution": "node",
"sourceMap": true,
"target": "es2015",
"target": "es6",
"declaration": false,
"outFile": "bin/tsdb-kit.js"
"skipLibCheck": true
},
"include": [ "src/**/*.ts" ],
"exclude": [ "src/index.ts" ]
"include": [ "src/**/*.ts" ]
}

6
lib.tsconfig.json

@ -2,9 +2,11 @@
"compilerOptions": {
"sourceMap": true,
"module": "commonjs",
"target": "es2015",
"moduleResolution": "node",
"target": "esnext",
"declaration": true,
"outDir": "lib"
"outDir": "lib",
"skipLibCheck": true
},
"include": [ "src/**/*.ts" ],
"exclude": [ "src/tsdb-kit" ]

5124
package-lock.json generated

File diff suppressed because it is too large Load Diff

19
package.json

@ -1,17 +1,18 @@
{
"name": "@corpglory/tsdb-kit",
"version": "1.1.1",
"version": "2.0.4",
"description": "",
"scripts": {
"build": "yarn build:lib && yarn build:bin",
"build:lib": "tsc --p lib.tsconfig.json",
"build:bin": "tsc --p bin.tsconfig.json",
"dev": "tsc -w",
"build:bin": "webpack --config webpack.config.js",
"dev:lib": "tsc --p lib.tsconfig.json -w",
"dev:bin": "webpack --watch --config webpack.config.js",
"test": "jest"
},
"repository": {
"type": "git",
"url": "git+https://github.com/CorpGlory/tsdb-kit.git"
"url": "git+https://code.corpglory.net/hastic/tsdb-kit.git"
},
"author": {
"name": "CorpGlory Inc."
@ -21,9 +22,9 @@
},
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/CorpGlory/tsdb-kit/issues"
"url": "https://code.corpglory.net/hastic/tsdb-kit/issues"
},
"homepage": "https://github.com/CorpGlory/tsdb-kit",
"homepage": "https://code.corpglory.net/hastic/tsdb-kit",
"dependencies": {
"axios": "^0.18.0",
"moment": "^2.22.2",
@ -32,9 +33,13 @@
"devDependencies": {
"@types/jest": "^26.0.15",
"@types/lodash": "^4.14.165",
"argparse": "^2.0.1",
"jest": "^26.6.3",
"ts-jest": "^26.4.4",
"typescript": "^4.1.2"
"ts-loader": "^9.3.1",
"typescript": "^4.1.2",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0"
},
"main": "./lib/index.js",
"bin": {

13
spec/elasticsearch.jest.ts

@ -1,6 +1,7 @@
import { ElasticsearchMetric } from '../src/metrics/elasticsearch_metric';
import { Datasource } from '../src/metrics/metric';
import { ElasticsearchConnector } from '../src/connectors/elasticsearch';
import { Datasource, DatasourceType } from '../src/connectors';
import 'jest';
import * as _ from 'lodash';
describe('simple query', function(){
@ -62,7 +63,7 @@ describe('simple query', function(){
}
}
}],
type: "elasticsearch"
type: DatasourceType.ELASTICSEARCH
};
datasource.data = datasource.data.map(d => JSON.stringify(d)).join('\n');
@ -162,7 +163,7 @@ describe('simple query', function(){
}
}];
let elasticMetric = new ElasticsearchMetric(datasource, targets);
let connector = new ElasticsearchConnector(datasource, targets);
it('check correct time processing', function() {
const expectedQueryTemplate = _.cloneDeep(queryTemplate);
@ -191,7 +192,7 @@ describe('simple query', function(){
}
};
let result = elasticMetric.getQuery(from, to, limit, offset);
let result = connector.getQuery(from, to, limit, offset);
expect(result).toEqual(expectedQuery);
});
@ -264,6 +265,6 @@ describe('simple query', function(){
]
};
expect(elasticMetric.getResults(result)).toEqual(expectedResult);
expect(connector.parseResponse(result)).toEqual(expectedResult);
});
});

10
spec/graphite.jest.ts

@ -1,11 +1,13 @@
import { Datasource, Metric } from '../src/index';
import { Datasource, DatasourceType } from '../src/index';
import { GraphiteConnector } from '../src/connectors/graphite';
import 'jest';
describe('correct Graphite query', function() {
let datasource: Datasource = {
url: 'http://example.com:1234',
type: 'graphite',
type: DatasourceType.GRAPHITE,
params: {
db: '',
q: '',
@ -15,10 +17,10 @@ describe('correct Graphite query', function() {
};
let target = `target=template(hosts.$hostname.cpu, hostname="worker1")`;
let query = new Metric(datasource, [target]);
let connector = new GraphiteConnector(datasource, [target]);
it("test simple query with time clause", function () {
expect(query.metricQuery.getQuery(1534809600000, 1537488000000, 500, 0).url).toBe(
expect(connector.getQuery(1534809600000, 1537488000000, 500, 0).url).toBe(
`${datasource.url}?target=${target}&from=1534809600&until=1537488000&maxDataPoints=500`
)
});

17
spec/targets.jest.ts → spec/influxdb.jest.ts

@ -1,4 +1,5 @@
import { Datasource, Metric } from '../src/index';
import { Datasource, DatasourceType } from '../src/index';
import { InfluxdbConnector } from '../src/connectors/influxdb';
import 'jest';
@ -6,7 +7,7 @@ import 'jest';
describe('Correct InfluxDB query', function() {
let datasource: Datasource = {
url: 'url',
type: 'influxdb',
type: DatasourceType.INFLUXDB,
params: {
db: 'db',
q: `SELECT mean("value") FROM "db" WHERE time > xxx AND time <= xxx LIMIT 100 OFFSET 20`,
@ -17,24 +18,24 @@ describe('Correct InfluxDB query', function() {
let target = 'mean("value")';
it("test query with two time expressions", function() {
let query = new Metric(datasource, [target]);
expect(query.metricQuery.getQuery(1534809600,1537488000,666,10).schema.params.q).toBe(
const connector = new InfluxdbConnector(datasource, [target]);
expect(connector.getQuery(1534809600,1537488000,666,10).schema.params.q).toBe(
`SELECT mean("value") FROM "db" WHERE time >= 1534809600ms AND time <= 1537488000ms LIMIT 666 OFFSET 10`
)
});
it('test query with one time expression', function() {
datasource.params.q = `SELECT mean("value") FROM "cpu_value" WHERE time >= now() - 6h GROUP BY time(30s) fill(null)`;
let query = new Metric(datasource, [target]);
expect(query.metricQuery.getQuery(1534809600,1537488000,666,10).schema.params.q).toBe(
const connector = new InfluxdbConnector(datasource, [target]);
expect(connector.getQuery(1534809600,1537488000,666,10).schema.params.q).toBe(
`SELECT mean("value") FROM "cpu_value" WHERE time >= 1534809600ms AND time <= 1537488000ms GROUP BY time(30s) fill(null) LIMIT 666 OFFSET 10`
)
});
it('test query with time expression', function() {
datasource.params.q = `SELECT mean("value") FROM "cpu_value" WHERE time>= now() - 6h AND time<xxx GROUP BY time(30s) fill(null)`;
let query = new Metric(datasource, [target]);
expect(query.metricQuery.getQuery(1534809600,1537488000,666,10).schema.params.q).toBe(
const connector = new InfluxdbConnector(datasource, [target]);
expect(connector.getQuery(1534809600,1537488000,666,10).schema.params.q).toBe(
`SELECT mean("value") FROM "cpu_value" WHERE time >= 1534809600ms AND time <= 1537488000ms GROUP BY time(30s) fill(null) LIMIT 666 OFFSET 10`
)
});

20
spec/prometheus.jest.ts

@ -1,15 +1,20 @@
import { PrometheusMetric } from '../src/metrics/prometheus_metric';
import { PrometheusConnector } from '../src/connectors/prometheus';
import { DatasourceType } from '../src/connectors';
import 'jest';
describe('Test Prometheus time range processing', function() {
let datasource = {
type: 'prometheus',
url: 'api/datasources/proxy/4/api/v1/query_range?query=node_disk_io_time_ms&start=1543411320&end=1543432950&step=30'
type: DatasourceType.PROMETHEUS,
url: 'api/datasources/proxy/4/api/v1/query_range?query=node_disk_io_time_ms&start=1543411320&end=1543432950&step=30',
auth: {
username: 'my_user',
password: 'my_password',
}
}
let targets = [];
let prometheus = new PrometheusMetric(datasource, targets);
let prometheus = new PrometheusConnector(datasource, targets);
it('check that from/to present in url', function() {
let from = 1234567891234; //milliseconds
@ -18,4 +23,11 @@ describe('Test Prometheus time range processing', function() {
expect(query.url.indexOf(`start=${Math.floor(from / 1000)}`) !== -1).toBeTruthy();
expect(query.url.indexOf(`end=${Math.floor(to / 1000)}`) !== -1).toBeTruthy();
});
it('check that username/password present in query', function() {
let query = prometheus.getQuery(0, 0, 1000, 0);
expect(query.auth?.username).toBe('my_user');
expect(query.auth?.password).toBe('my_password');
})
});

125
spec/postgres.jest.ts → spec/sql.jest.ts

@ -1,5 +1,5 @@
import { PostgresMetric } from '../src/metrics/postgres_metric';
import { MetricQuery } from '../src/metrics/metric';
import { SqlConnector } from '../src/connectors/sql';
import { DatasourceType, DatasourceQuery } from '../src/connectors';
import 'jest';
import * as _ from 'lodash';
@ -11,8 +11,8 @@ describe('Test query creation', function() {
let offset = 0;
let from = 1542983750857;
let to = 1542984313292;
let postgres = getMetricForSqlQuery();
let mQuery: MetricQuery = postgres.getQuery(from, to, limit, offset);
let connector = getConnectorForSqlQuery();
let mQuery: DatasourceQuery = connector.getQuery(from, to, limit, offset);
it('test that payload placed to data field', function() {
expect('data' in mQuery.schema).toBeTruthy();
@ -31,37 +31,55 @@ describe('Test query creation', function() {
});
describe('Test result parsing', function() {
let postgres = getMetricForSqlQuery();
let connector = getConnectorForSqlQuery();
let timestamps = [1542983800000, 1542983800060, 1542983800120]
let response = {
data: {
results: {
A: {
refId: 'A',
meta: {
rowCount:0,
sql: 'SELECT "time" AS "time", val FROM local ORDER BY 1'
},
series: [
frames: [
{
name:"val",
points: [
[622, timestamps[0]],
[844, timestamps[1]],
[648, timestamps[2]]
]
schema: {
refId: 'A',
meta: {
'executedQueryString': 'SELECT\n \"time\" AS \"time\",\n eur\nFROM rate_test\nWHERE\n \"time\" >= 1669648679 AND \"time\" <= 1672240679\nORDER BY 1'
},
fields: [
{
name: 'Time',
type: 'time',
typeInfo: {
frame: 'time.Time',
nullable: true
}
},
{
name: 'eur',
type: 'number',
typeInfo: {
frame: 'float64',
nullable: true
}
}
]
},
data: {
values: [
[ timestamps[0], timestamps[1], timestamps[2] ],
[ 1.53, 1.17, 1.17 ],
]
}
}
],
tables: 'null'
]
}
}
}
}
let result = postgres.getResults(response);
let result = connector.parseResponse(response);
it('check results columns order', function() {
let timestampColumnNumber = result.columns.indexOf('timestamp');
let timestampColumnNumber = result.columns.indexOf('Time');
expect(result.values.map(v => v[timestampColumnNumber])).toEqual(timestamps);
});
});
@ -144,6 +162,63 @@ describe('Test sql processing', function() {
check(original, expected);
});
it('sql with $__timeGroup aggregation', function () {
const original = `SELECT
$__timeGroup("time", $__interval, NULL),
avg("metric") AS "Réseau"
FROM metric_values
WHERE $__timeFilter("time")
GROUP BY 1
ORDER BY 1`;
const expected = `SELECT
"time",
avg("metric") AS "Réseau"
FROM metric_values
WHERE $__timeFilter("time")
GROUP BY 1
ORDER BY 1 LIMIT ${limit} OFFSET ${offset}`;
check(original, expected);
});
it('sql with $__timeGroupAlias aggregation', function () {
const original = `SELECT
$__timeGroupAlias("time", $__interval),
avg("metric") AS "Réseau"
FROM metric_values
WHERE $__timeFilter("time")
GROUP BY 1
ORDER BY 1`;
const expected = `SELECT
"time",
avg("metric") AS "Réseau"
FROM metric_values
WHERE $__timeFilter("time")
GROUP BY 1
ORDER BY 1 LIMIT ${limit} OFFSET ${offset}`;
check(original, expected);
});
it('sql with $__timeGroupAlias aggregation and linebreaks', function () {
const original = `SELECT
$__timeGroupAlias(
any_field,
$__interval
),
avg("metric") AS "Réseau"
FROM metric_values
WHERE $__timeFilter(any_field)
GROUP BY 1
ORDER BY 1`;
const expected = `SELECT
any_field,
avg("metric") AS "Réseau"
FROM metric_values
WHERE $__timeFilter(any_field)
GROUP BY 1
ORDER BY 1 LIMIT ${limit} OFFSET ${offset}`;
check(original, expected);
});
it('complex sql with one select', function() {
let original = `SELECT
statistics.created_at as time,
@ -216,11 +291,11 @@ describe('Test sql processing', function() {
});
function checkExpectation(original: string, expected: string, from: number, to: number, limit: number, offset: number) {
let metric = getMetricForSqlQuery(original);
let metric = getConnectorForSqlQuery(original);
expect(metric.getQuery(from, to, limit, offset).schema.data.queries[0].rawSql).toBe(expected);
}
function getMetricForSqlQuery(query: string = ''): PostgresMetric {
function getConnectorForSqlQuery(query: string = ''): SqlConnector {
const queryPayload = {
from: 1542983750857,
to: 1542984313292
@ -228,7 +303,7 @@ function getMetricForSqlQuery(query: string = ''): PostgresMetric {
const datasource = {
url: 'api/tsdb/query',
type: 'postgres',
type: DatasourceType.POSTGRES,
data: queryPayload
};
@ -241,5 +316,5 @@ function getMetricForSqlQuery(query: string = ''): PostgresMetric {
format: 'time_series'
}];
return new PostgresMetric(datasource, targets);
return new SqlConnector(datasource, targets);
}

2
spec/utils.jest.ts

@ -1,4 +1,4 @@
import { processSQLLimitOffset } from '../src/metrics/utils';
import { processSQLLimitOffset } from '../src/connectors/utils';
import 'jest';

31
src/connectors/connector_factory.ts

@ -0,0 +1,31 @@
import { InfluxdbConnector } from './influxdb';
import { GraphiteConnector } from './graphite';
import { DatasourceConnector, DatasourceType } from '.';
import { PrometheusConnector } from './prometheus';
import { PostgresConnector } from './postgres';
import { ElasticsearchConnector } from './elasticsearch';
import { MysqlConnector } from './mysql';
import { QueryConfig } from '../models/query_config';
export function connectorFactory(
queryConfig: QueryConfig,
): DatasourceConnector {
const classMap = {
[DatasourceType.INFLUXDB]: InfluxdbConnector,
[DatasourceType.GRAPHITE]: GraphiteConnector,
[DatasourceType.PROMETHEUS]: PrometheusConnector,
[DatasourceType.POSTGRES]: PostgresConnector,
[DatasourceType.ELASTICSEARCH]: ElasticsearchConnector,
[DatasourceType.MYSQL]: MysqlConnector,
};
const datasource = queryConfig.datasource;
const targets = queryConfig.targets;
if(classMap[datasource.type] === undefined) {
console.error(`Datasources of type ${datasource.type} are not supported currently`);
throw new Error(`Datasources of type ${datasource.type} are not supported currently`);
} else {
return new classMap[datasource.type](datasource, targets);
}
}

44
src/metrics/elasticsearch_metric.ts → src/connectors/elasticsearch.ts

@ -1,12 +1,12 @@
import { AbstractMetric, Datasource, MetricId, MetricQuery, MetricResults } from './metric';
import { DataKitError } from '../grafana_service';
import { DatasourceConnector, Datasource, DatasourceQuery, DataTable } from '.';
import { TsdbKitError } from '../types';
import * as _ from 'lodash';
export type RangeFilter = { range: { [key: string]: { gte: String, lte: String } } };
export type QueryStringFilter = { query_string: { analyze_wildcard: Boolean, query: String } };
export type QueryConfig = {
export type ElasticsearchQuery = {
size: number,
query: {
bool: {
@ -18,33 +18,33 @@ export type QueryConfig = {
export type Aggregation = {
date_histogram: {
interval: String,
field: String,
min_doc_count: Number,
extended_bounds: { min: String, max: String },
format: String
interval: string,
field: string,
min_doc_count: number,
extended_bounds: { min: string, max: string },
format: string
}
};
const DATE_HISTOGRAM_FIELD = 'date_histogram';
export class ElasticsearchMetric extends AbstractMetric {
constructor(datasource: Datasource, targets: any[], id?: MetricId) {
super(datasource, targets, id);
export class ElasticsearchConnector extends DatasourceConnector {
constructor(datasource: Datasource, targets: any[]) {
super(datasource, targets);
}
getQuery(from: number, to: number, limit: number, offset: number): MetricQuery {
getQuery(from: number, to: number, limit: number, offset: number): DatasourceQuery {
let data = this.datasource.data.split('\n').map(d => d === '' ? d: JSON.parse(d));
if(data.length === 0) {
throw new DataKitError('Datasource data is empty');
throw new TsdbKitError('Datasource data is empty');
}
const queryConfig: QueryConfig = data[1];
const query: ElasticsearchQuery = data[1];
queryConfig.size = 0;
let timeField = null;
query.size = 0;
let timeField: string | null = null;
let aggs = _.filter(queryConfig.aggs, f => _.has(f, DATE_HISTOGRAM_FIELD));
let aggs = _.filter(query.aggs, f => _.has(f, DATE_HISTOGRAM_FIELD));
_.each(aggs, (agg: Aggregation) => {
agg[DATE_HISTOGRAM_FIELD].extended_bounds = {
min: from.toString(),
@ -63,9 +63,9 @@ export class ElasticsearchMetric extends AbstractMetric {
throw new Error('datasource time field not found');
}
let filters = queryConfig.query.bool.filter.filter(f => _.has(f, 'range')) as RangeFilter[];
let filters = query.query.bool.filter.filter(f => _.has(f, 'range')) as RangeFilter[];
if(filters.length === 0) {
throw new DataKitError('Empty filters');
throw new TsdbKitError('Empty filters');
}
let range = filters[0].range;
range[timeField].gte = from.toString();
@ -86,7 +86,7 @@ export class ElasticsearchMetric extends AbstractMetric {
}
}
getResults(res): MetricResults {
parseResponse(res): DataTable {
let columns = ['timestamp', 'target'];
let values = [];
@ -106,7 +106,7 @@ export class ElasticsearchMetric extends AbstractMetric {
const bucketAggs = JSON.stringify(this.targets[0].bucketAggs);
const aggregationKeys = JSON.stringify(_.keys(aggregations));
console.error(`can't find related aggregation id. bucketAggs:${bucketAggs} aggregationKeys:${aggregationKeys}`);
throw new DataKitError(`can't find related aggregation id`);
throw new TsdbKitError(`can't find related aggregation id`);
} else {
aggrgAgg = aggrgAgg[0].id;
}
@ -114,7 +114,7 @@ export class ElasticsearchMetric extends AbstractMetric {
let agg = this.targets[0].metrics.filter(m => !m.hide).map(m => m.id);
if(agg.length > 1) {
throw new DataKitError(`multiple series for metric are not supported currently: ${JSON.stringify(agg)}`);
throw new TsdbKitError(`multiple series for metric are not supported currently: ${JSON.stringify(agg)}`);
}
agg = agg[0];

12
src/metrics/graphite_metric.ts → src/connectors/graphite.ts

@ -1,14 +1,14 @@
import { AbstractMetric, Datasource, MetricId, MetricQuery, MetricResults } from './metric';
import { DatasourceConnector, Datasource, DatasourceQuery, DataTable } from '.';
import * as _ from 'lodash';
export class GraphiteMetric extends AbstractMetric {
constructor(datasource: Datasource, targets: any[], id?: MetricId) {
super(datasource, targets, id);
export class GraphiteConnector extends DatasourceConnector {
constructor(datasource: Datasource, targets: any[]) {
super(datasource, targets);
}
getQuery(from: number, to: number, limit: number, offset: number): MetricQuery {
getQuery(from: number, to: number, limit: number, offset: number): DatasourceQuery {
let fromDate = Math.floor(from / 1000);
let toDate = Math.floor(to / 1000);
@ -42,7 +42,7 @@ export class GraphiteMetric extends AbstractMetric {
}
}
getResults(res): MetricResults {
parseResponse(res): DataTable {
if(res.data === undefined || res.data.length < 1) {
console.log('datasource return empty response, no data');

58
src/connectors/index.ts

@ -0,0 +1,58 @@
export enum QueryType {
DIRECT = 'direct',
GRAFANA = 'grafana',
}
export enum DatasourceType {
INFLUXDB = 'influxdb',
GRAPHITE = 'graphite',
PROMETHEUS = 'prometheus',
POSTGRES = 'postgres',
ELASTICSEARCH = 'elasticsearch',
MYSQL = 'mysql',
}
// TODO: Datasource: type -> class
export declare type Datasource = {
url: string;
type: DatasourceType;
params?: {
db: string;
q: string;
epoch: string;
};
data?: any;
datasourceId?: string;
auth?: any;
};
export type DatasourceQuery = {
url: string;
method: string;
schema: any;
headers?: any;
auth?: {
username: string;
password: string;
};
}
export type DataTable = {
values: (number | null)[][];
columns: string[];
}
export abstract class DatasourceConnector {
constructor(
public datasource: Datasource,
// TODO: Target type
public targets: any[],
) {}
/*
from / to - timestamp in ms
limit - max number of items in result
offset - number of items to skip from timerange start
*/
abstract getQuery(from: number, to: number, limit: number, offset: number): DatasourceQuery;
abstract parseResponse(res): DataTable;
}

13
src/metrics/influxdb_metric.ts → src/connectors/influxdb.ts

@ -1,16 +1,15 @@
import { AbstractMetric, Datasource, MetricId, MetricQuery, MetricResults } from "./metric";
import { DatasourceConnector, Datasource, DatasourceQuery, DataTable } from '.';
import { processSQLLimitOffset } from './utils';
const INFLUX_QUERY_TIME_REGEX = /time ?[><=]+ ?[^A-Z]+(AND ?time ?[><=]+ ?[^A-Z]+)?/;
export class InfluxdbMetric extends AbstractMetric {
export class InfluxdbConnector extends DatasourceConnector {
private _queryParts: string[];
constructor(datasource: Datasource, targets: any[], id?: MetricId) {
super(datasource, targets, id);
constructor(datasource: Datasource, targets: any[]) {
super(datasource, targets);
var queryStr = datasource.params.q;
this._queryParts = queryStr.split(INFLUX_QUERY_TIME_REGEX);
@ -24,7 +23,7 @@ export class InfluxdbMetric extends AbstractMetric {
}
}
getQuery(from: number, to: number, limit: number, offset: number): MetricQuery {
getQuery(from: number, to: number, limit: number, offset: number): DatasourceQuery {
let timeClause = `time >= ${from}ms AND time <= ${to}ms`;
let q = `${this._queryParts[0]} ${timeClause} ${this._queryParts[2]}`;
q = processSQLLimitOffset(q, limit, offset);
@ -41,7 +40,7 @@ export class InfluxdbMetric extends AbstractMetric {
}
}
getResults(res): MetricResults {
parseResponse(res): DataTable {
let emptyResult = {
columns: ['timestamp', 'target'],
values: []

5
src/connectors/mysql.ts

@ -0,0 +1,5 @@
import { SqlConnector } from './sql';
export class MysqlConnector extends SqlConnector {
}

5
src/connectors/postgres.ts

@ -0,0 +1,5 @@
import { SqlConnector } from './sql';
export class PostgresConnector extends SqlConnector {
}

28
src/metrics/prometheus_metric.ts → src/connectors/prometheus.ts

@ -1,15 +1,15 @@
import { AbstractMetric, Datasource, MetricId, MetricQuery, MetricResults } from './metric';
import { DatasourceConnector, Datasource, DatasourceQuery, DataTable } from '.';
const QUERY_TIME_REGEX = /\&start=[^\&]*\&end=[^\&]*\&/;
export class PrometheusMetric extends AbstractMetric {
export class PrometheusConnector extends DatasourceConnector {
constructor(datasource: Datasource, targets: any[], id?: MetricId) {
super(datasource, targets, id);
constructor(datasource: Datasource, targets: any[]) {
super(datasource, targets);
}
getQuery(from: number, to: number, limit: number, offset: number): MetricQuery {
getQuery(from: number, to: number, limit: number, offset: number): DatasourceQuery {
let url = this.datasource.url;
from = Math.floor(from / 1000); //prometheus uses seconds for timestamp
to = Math.floor(to / 1000);
@ -21,11 +21,12 @@ export class PrometheusMetric extends AbstractMetric {
method: 'GET',
schema: {
params: this.datasource.params
}
},
auth: this.datasource.auth,
}
}
getResults(res): MetricResults {
parseResponse(res): DataTable {
if(res.data === undefined || res.data.data.result.length < 1) {
console.log('datasource return empty response, no data');
@ -36,13 +37,13 @@ export class PrometheusMetric extends AbstractMetric {
}
let result = res.data.data.result;
let result_matrix = {
let result_matrix: DataTable = {
columns: ['timestamp'],
values: []
};
result.map(r => {
let keys = [];
let keys: string[] = [];
for(let key in r.metric) {
keys.push(`${key}=${r.metric[key]}`);
}
@ -51,8 +52,8 @@ export class PrometheusMetric extends AbstractMetric {
let values = result.map(r => r.values);
let timestamps = [];
values.map(v => v.map(row => timestamps.push(row[0])));
let timestamps: (number | null)[] = [];
values.forEach(v => v.forEach((row: number[]) => timestamps.push(row[0])));
timestamps = timestamps.filter(function(item, i, ar) {
return ar.indexOf(item) === i; //uniq values
});
@ -70,12 +71,11 @@ export class PrometheusMetric extends AbstractMetric {
if(currentTimestamp === t) {
row.push(+currentValue);
v.shift();
}
else {
} else {
row.push(null);
}
});
row[0] = +row[0] * 1000; //convert timestamp to ms
row[0] = +(row[0] as number) * 1000; //convert timestamp to ms
result_matrix.values.push(row);
};
return result_matrix;

31
src/metrics/sql_metric.ts → src/connectors/sql.ts

@ -1,15 +1,17 @@
import { AbstractMetric, Datasource, MetricId, MetricQuery, MetricResults } from './metric';
import { DatasourceConnector, Datasource, DatasourceQuery, DataTable } from '.';
import { processSQLLimitOffset } from './utils';
import * as _ from 'lodash';
// for 26.09.2020 it works for all SQL datasources
export class SqlMetric extends AbstractMetric {
// as of 26.09.2020, it works for all SQL datasources
export class SqlConnector extends DatasourceConnector {
private _targetName: string; //save first target name, while multi metric not implemented
private url: string = 'api/tsdb/query';
private url: string;
constructor(datasource: Datasource, targets: any[], id?: MetricId) {
super(datasource, targets, id);
constructor(datasource: Datasource, targets: any[]) {
super(datasource, targets);
this.url = datasource.url;
if(targets.length === 0) {
throw Error('got empty targets list');
@ -17,7 +19,7 @@ export class SqlMetric extends AbstractMetric {
this._targetName = targets[0].refId;
}
getQuery(from: number, to: number, limit: number, offset: number): MetricQuery {
getQuery(from: number, to: number, limit: number, offset: number): DatasourceQuery {
let queries = this.targets;
_.forEach(queries, q => {
@ -34,13 +36,13 @@ export class SqlMetric extends AbstractMetric {
data: {
from: String(from),
to: String(to),
queries: queries
queries: queries,
}
}
};
}
getResults(res): MetricResults {
parseResponse(res): DataTable {
let emptyResult = {
columns: ['timestamp', 'target'],
values: []
@ -53,16 +55,15 @@ export class SqlMetric extends AbstractMetric {
// TODO: support more than 1 metric (each res.data.results item is a metric)
let results = res.data.results[this._targetName];
if (!results.series) {
if (_.isEmpty(results.frames)) {
return emptyResult;
}
let points = results.series[0].points;
points.forEach(p => p.reverse());
const frame = results.frames[0];
return {
columns: ['timestamp', results.series[0].name],
values: points
columns: frame.schema.fields.map(field => field.name),
// @ts-ignore
values: _.zip(...frame.data.values),
};
}
}

8
src/metrics/utils.ts → src/connectors/utils.ts

@ -8,6 +8,12 @@ export function processSQLLimitOffset(sql: string, limit: number, offset: number
}
sql = splits[0]; // removes ";" from EOL
const reAggregation = /\$__timeGroup(?:Alias)?\(\s*([^,]+)\s*,\s*\$__interval[^\)]*\)/igm;
const occurence = reAggregation.exec(sql);
if(occurence) {
sql = sql.replace(reAggregation, occurence[1]);
}
let relim = /limit [0-9]+/ig;
let reoff = /offset [0-9]+/ig;
@ -32,7 +38,7 @@ export function processSQLLimitOffset(sql: string, limit: number, offset: number
}
function ensureParentheses(regex: RegExp, str: string): { index: number, length: number } {
let occurence: RegExpExecArray;
let occurence: RegExpExecArray | null;
while((occurence = regex.exec(str)) !== null) {
let leftPart = str.slice(0, occurence.index)
let rightPart = str.slice(occurence.index + occurence[0].length);

134
src/grafana_service.ts

@ -1,134 +0,0 @@
import { Metric } from './metrics/metrics_factory';
import { MetricQuery, Datasource } from './metrics/metric';
import { URL } from 'url';
import axios from 'axios';
import * as _ from 'lodash';
export class DataKitError extends Error {
constructor(
message: string,
public datasourceType?: string,
public datasourceUrl?: string
) {
super(message);
}
};
export class BadRange extends DataKitError {};
export class GrafanaUnavailable extends DataKitError {};
export class DatasourceUnavailable extends DataKitError {};
const CHUNK_SIZE = 50000;
/**
* @param metric to query to Grafana
* @returns { values: [time, value][], columns: string[] }
*/
export async function queryByMetric(
metric: Metric, url: string, from: number, to: number, apiKey: string
): Promise<{ values: [number, number][], columns: string[] }> {
if(from > to) {
throw new BadRange(
`Data-kit got wrong range: from ${from} > to ${to}`,
metric.datasource.type,
url
);
}
if(from === to) {
console.warn(`Data-kit got from === to`);
}
const grafanaUrl = getGrafanaUrl(url);
let data = {
values: [],
columns: []
};
while(true) {
let query = metric.metricQuery.getQuery(from, to, CHUNK_SIZE, data.values.length);
query.url = `${grafanaUrl}/${query.url}`;
let res = await queryGrafana(query, apiKey, metric.datasource);
let chunk = metric.metricQuery.getResults(res);
let values = chunk.values;
data.values = data.values.concat(values);
data.columns = chunk.columns;
if(values.length < CHUNK_SIZE) {
// because if we get less that we could, then there is nothing more
break;
}
}
return data;
}
async function queryGrafana(query: MetricQuery, apiKey: string, datasource: Datasource) {
let headers = { Authorization: `Bearer ${apiKey}` };
if(query.headers !== undefined) {
_.merge(headers, query.headers);
}
let axiosQuery = {
headers,
url: query.url,
method: query.method,
};
_.defaults(axiosQuery, query.schema);
try {
var res = await axios(axiosQuery);
} catch (e) {
const msg = `Data kit: fail while request data: ${e.message}`;
const parsedUrl = new URL(query.url);
const queryUrl = `query url: ${JSON.stringify(parsedUrl.pathname)}`;
console.error(`${msg} ${queryUrl}`);
if(e.errno === 'ECONNREFUSED') {
throw new GrafanaUnavailable(e.message);
}
if(e.response !== undefined) {
console.error(`Response: \
status: ${e.response.status}, \
response data: ${JSON.stringify(e.response.data)}, \
headers: ${JSON.stringify(e.response.headers)}
`);
if(e.response.status === 401) {
throw new Error(`Unauthorized. Check the API_KEY. ${e.message}`);
}
if(e.response.status === 502) {
let datasourceError = new DatasourceUnavailable(
`datasource ${parsedUrl.pathname} unavailable, message: ${e.message}`,
datasource.type,
query.url
);
throw datasourceError;
}
}
throw new Error(msg);
}
return res;
}
function getGrafanaUrl(url: string) {
const parsedUrl = new URL(url);
const path = parsedUrl.pathname;
const panelUrl = path.match(/^\/*([^\/]*)\/d\//);
if(panelUrl === null) {
return url;
}
const origin = parsedUrl.origin;
const grafanaSubPath = panelUrl[1];
if(grafanaSubPath.length > 0) {
return `${origin}/${grafanaSubPath}`;
}
return origin;
}

58
src/index.ts

@ -1,3 +1,55 @@
export { Metric } from './metrics/metrics_factory';
export { Datasource } from './metrics/metric'
export { queryByMetric, GrafanaUnavailable, DatasourceUnavailable } from './grafana_service';
import { DataTable } from './connectors';
import { QueryConfig } from './models/query_config';
import { BadRange } from './types';
export { QueryConfig } from './models/query_config';
export { Datasource, DatasourceType, DataTable } from './connectors'
export { DatasourceUnavailable } from './types';
export { GrafanaUnavailable } from './services/query_service/grafana';
const CHUNK_SIZE = 50000;
/**
* @param queryConfig
* @returns { values: [time, value][], columns: string[] }
*/
export async function queryByConfig(
// TODO: check how did we wanna use `url` field
queryConfig: QueryConfig, url: string, from: number, to: number,
// TODO: we need an abstract DatasourceConfig class which will differ in direct and grafana queries
apiKey?: string
): Promise<DataTable> {
if(from > to) {
throw new BadRange(
`TSDB-kit got wrong range: from ${from} > to ${to}`,
queryConfig.datasource.type,
url
);
}
if(from === to) {
console.warn(`TSDB-kit got from === to`);
}
let data: DataTable = {
values: [],
columns: []
};
while(true) {
let query = queryConfig.datasourceConnector.getQuery(from, to, CHUNK_SIZE, data.values.length);
const res = await queryConfig.queryService.query(query, apiKey);
let chunk = queryConfig.datasourceConnector.parseResponse(res);
let values = chunk.values;
data.values = data.values.concat(values);
data.columns = chunk.columns;
if(values.length < CHUNK_SIZE) {
// because if we get less that we could, then there is nothing more
break;
}
}
return data;
}

40
src/metrics/metric.ts

@ -1,40 +0,0 @@
export declare type Datasource = {
url: string;
type: string;
params?: {
db: string;
q: string;
epoch: string;
};
data?: any;
datasourceId?: string;
};
export type MetricQuery = {
url: string;
method: string;
schema: any;
headers?: any;
}
export type MetricResults = {
values: any;
columns: any;
}
export type MetricId = string;
export abstract class AbstractMetric {
constructor(
public datasource: Datasource,
public targets: any[],
public id?: MetricId
) {};
abstract getQuery(from: number, to: number, limit: number, offset: number): MetricQuery;
/*
from / to - timestamp in ms
limit - max number of items in result
offset - number of items to skip from timerange start
*/
abstract getResults(res): MetricResults;
}

78
src/metrics/metrics_factory.ts

@ -1,78 +0,0 @@
import { InfluxdbMetric } from './influxdb_metric';
import { GraphiteMetric } from './graphite_metric';
import { AbstractMetric, Datasource, MetricId } from './metric';
import { PrometheusMetric } from './prometheus_metric';
import { PostgresMetric } from './postgres_metric';
import { ElasticsearchMetric } from './elasticsearch_metric';
import { MysqlMetric } from './mysql_metric';
export function metricFactory(
datasource: Datasource,
targets: any[],
id?: MetricId
): AbstractMetric {
let classMap = {
'influxdb': InfluxdbMetric,
'graphite': GraphiteMetric,
'prometheus': PrometheusMetric,
'postgres': PostgresMetric,
'elasticsearch': ElasticsearchMetric,
'mysql': MysqlMetric,
};
if(classMap[datasource.type] === undefined) {
console.error(`Datasources of type ${datasource.type} are not supported currently`);
throw new Error(`Datasources of type ${datasource.type} are not supported currently`);
} else {
return new classMap[datasource.type](datasource, targets, id);
}
}
export class Metric {
datasource: Datasource;
targets: any[];
id?: MetricId;
private _metricQuery: AbstractMetric = undefined;
constructor(datasource: Datasource, targets: any[], id?: MetricId) {
if(datasource === undefined) {
throw new Error('datasource is undefined');
}
if(targets === undefined) {
throw new Error('targets is undefined');
}
if(targets.length === 0) {
throw new Error('targets is empty');
}
this.datasource = datasource;
this.targets = targets;
this.id = id;
}
public get metricQuery() {
if(this._metricQuery === undefined) {
this._metricQuery = metricFactory(this.datasource, this.targets, this.id);
}
return this._metricQuery;
}
public toObject() {
return {
datasource: this.datasource,
targets: this.targets,
_id: this.id
};
}
static fromObject(obj: any): Metric {
if(obj === undefined) {
throw new Error('obj is undefined');
}
return new Metric(
obj.datasource,
obj.targets,
obj._id
);
}
}

5
src/metrics/mysql_metric.ts

@ -1,5 +0,0 @@
import { SqlMetric } from './sql_metric';
export class MysqlMetric extends SqlMetric {
}

5
src/metrics/postgres_metric.ts

@ -1,5 +0,0 @@
import { SqlMetric } from './sql_metric';
export class PostgresMetric extends SqlMetric {
}

62
src/models/query_config.ts

@ -0,0 +1,62 @@
import { Datasource, DatasourceConnector, QueryType } from '../connectors';
import { connectorFactory } from '../connectors/connector_factory';
import { QueryService } from '../services/query_service/base';
import { queryServiceFactory } from '../services/query_service/query_service_factory';
export class QueryConfig {
queryType: QueryType;
datasource: Datasource;
// TODO: Target type (depends on datasource type)
targets: any[];
private _datasourceConnector?: DatasourceConnector;
private _queryService?: QueryService;
constructor(queryType: QueryType, datasource: Datasource, targets: any[]) {
if(queryType === undefined) {
throw new Error('queryType is undefined');
}
if(datasource === undefined) {
throw new Error('datasource is undefined');
}
if(targets === undefined) {
throw new Error('targets is undefined');
}
this.queryType = queryType;
this.datasource = datasource;
this.targets = targets;
}
get datasourceConnector(): DatasourceConnector {
if(this._datasourceConnector === undefined) {
this._datasourceConnector = connectorFactory(this);
}
return this._datasourceConnector;
}
get queryService(): QueryService {
if(this._queryService === undefined) {
this._queryService = queryServiceFactory(this);
}
return this._queryService;
}
public toObject() {
return {
queryType: this.queryType,
datasource: this.datasource,
targets: this.targets,
};
}
static fromObject(obj: any): QueryConfig {
if(obj === undefined) {
throw new Error('obj is undefined');
}
return new QueryConfig(
obj.queryType,
obj.datasource,
obj.targets,
);
}
}

11
src/services/query_service/base.ts

@ -0,0 +1,11 @@
import { Datasource, DatasourceQuery } from '../../connectors';
import { AxiosResponse } from 'axios';
export abstract class QueryService {
constructor(protected _datasource: Datasource) { }
// TODO: we don't need `apiKey` here, we need some abstract auth config for both Direct and Grafana queries
abstract query(query: DatasourceQuery, apiKey?: string): Promise<AxiosResponse<any>>;
}

52
src/services/query_service/direct.ts

@ -0,0 +1,52 @@
import { QueryService } from './base';
import { DatasourceUnavailable } from '../../types';
import { Datasource, DatasourceQuery } from '../../connectors';
import axios, { AxiosResponse } from 'axios';
import * as _ from 'lodash';
export class DirectQueryService extends QueryService {
constructor(datasource: Datasource) {
super(datasource);
}
async query(query: DatasourceQuery): Promise<AxiosResponse<any>> {
// TODO: support auth
let axiosQuery = {
...query,
};
_.defaults(axiosQuery, query.schema);
try {
return axios(axiosQuery);
} catch(e) {
// TODO: seems like this error handler can be used for both Grafana and Direct queries
const msg = `TSDB-kit: fail while request data: ${e.message}`;
const parsedUrl = new URL(query.url);
const queryUrl = `query url: ${JSON.stringify(parsedUrl.pathname)}`;
console.error(`${msg} ${queryUrl}`);
if(e.response !== undefined) {
console.error(`Response: \
status: ${e.response.status}, \
response data: ${JSON.stringify(e.response.data)}, \
headers: ${JSON.stringify(e.response.headers)}
`);
if(e.response.status === 401) {
throw new Error(`Unauthorized. Check credentials. ${e.message}`);
}
if(e.response.status === 502) {
let datasourceError = new DatasourceUnavailable(
`datasource ${parsedUrl.pathname} unavailable, message: ${e.message}`,
this._datasource.type,
query.url
);
throw datasourceError;
}
}
throw new Error(msg);
}
}
}

64
src/services/query_service/grafana.ts

@ -0,0 +1,64 @@
import { QueryService } from './base';
import { Datasource, DatasourceQuery } from '../../connectors';
import { TsdbKitError, DatasourceUnavailable } from '../../types';
import axios, { AxiosResponse } from 'axios';
import * as _ from 'lodash';
export class GrafanaUnavailable extends TsdbKitError { };
export class GrafanaQueryService extends QueryService {
constructor(datasource: Datasource) {
super(datasource);
}
async query(query: DatasourceQuery, apiKey: string): Promise<AxiosResponse<any>> {
let headers = { Authorization: `Bearer ${apiKey}` };
if(query.headers !== undefined) {
_.merge(headers, query.headers);
}
let axiosQuery = {
headers,
url: query.url,
method: query.method,
};
_.defaults(axiosQuery, query.schema);
try {
const resp = await axios(axiosQuery);
return resp;
} catch (e) {
// TODO: seems like this error handler can be used for both Grafana and Direct queries
const msg = `TSDB-kit: fail while request data: ${e.message}`;
const parsedUrl = new URL(query.url);
const queryUrl = `query url: ${JSON.stringify(parsedUrl.pathname)}`;
console.error(`${msg} ${queryUrl}`);
if(e.errno === 'ECONNREFUSED') {
throw new GrafanaUnavailable(e.message);
}
if(e.response !== undefined) {
console.error(`Response: \
status: ${e.response.status}, \
response data: ${JSON.stringify(e.response.data)}, \
headers: ${JSON.stringify(e.response.headers)}
`);
if(e.response.status === 401) {
throw new Error(`Unauthorized. Check the API_KEY. ${e.message}`);
}
if(e.response.status === 502) {
let datasourceError = new DatasourceUnavailable(
`datasource ${parsedUrl.pathname} unavailable, message: ${e.message}`,
this._datasource.type,
query.url
);
throw datasourceError;
}
}
throw new Error(msg);
}
}
}

23
src/services/query_service/query_service_factory.ts

@ -0,0 +1,23 @@
import { QueryService } from './base';
import { DirectQueryService } from './direct';
import { GrafanaQueryService } from './grafana';
import { QueryType } from '../../connectors';
import { QueryConfig } from '../../models/query_config';
export function queryServiceFactory(
queryConfig: QueryConfig,
): QueryService {
const classMap = {
[QueryType.DIRECT]: DirectQueryService,
[QueryType.GRAFANA]: GrafanaQueryService,
};
const queryType = queryConfig.queryType;
const datasource = queryConfig.datasource;
if(classMap[queryType] === undefined) {
console.error(`Queries of type ${queryType} are not supported currently`);
throw new Error(`Queries of type ${queryType} are not supported currently`);
} else {
return new classMap[queryType](datasource);
}
}

50
src/tsdb-kit/index.ts

@ -1 +1,49 @@
console.log('Hello world');
import { queryByConfig, QueryConfig } from '..';
import { DatasourceType, QueryType } from '../connectors';
const { version } = require('../../package.json')
import { ArgumentParser } from 'argparse';
import * as _ from 'lodash';
const parser = new ArgumentParser();
parser.add_argument('-v', '--version', { action: 'version', version });
parser.add_argument('-U', '--url', { help: 'Datasource URL', required: true });
parser.add_argument('-q', '--query', { help: 'Query Template', required: true });
parser.add_argument('-f', '--from', { help: 'From timestamp (ms), e.g. 1660670020000. If not specified, `now-5m` is used' });
parser.add_argument('-t', '--to', { help: 'To timestamp (ms), e.g. 1660670026000. If not specified, `now` is used' });
parser.add_argument('-u', '--username', { help: 'Basic Auth Username' });
parser.add_argument('-p', '--password', { help: 'Basic Auth Password' });
const args = parser.parse_args();
const timeNowInMs = new Date().getTime();
const PROMETHEUS_URL = args.url;
const QUERY = args.query;
const FROM = args.from || timeNowInMs - 5 * 60 * 1000;
const TO = args.to || timeNowInMs;
const USERNAME = args.username;
const PASSWORD = args.password;
let auth;
if(USERNAME && PASSWORD) {
auth = { username: USERNAME, password: PASSWORD };
}
const datasource = {
type: DatasourceType.PROMETHEUS,
// TODO: remove PROMETHEUS_URL from here
url: `${PROMETHEUS_URL}/api/v1/query_range?query=${QUERY}&start=1543411320&end=1543432950&step=30`,
auth,
};
const targets = [];
const queryConfig = new QueryConfig(QueryType.DIRECT, datasource, targets);
queryByConfig(queryConfig, PROMETHEUS_URL, FROM, TO)
.then(res => {
console.log(res);
})
.catch(err => {
console.error('Query error: ', err);
});

15
src/types.ts

@ -0,0 +1,15 @@
import { DatasourceType } from './connectors';
export class TsdbKitError extends Error {
constructor(
message: string,
public datasourceType?: DatasourceType,
public datasourceUrl?: string
) {
super(message);
}
};
export class BadRange extends TsdbKitError {};
export class DatasourceUnavailable extends TsdbKitError {};

33
webpack.config.js

@ -0,0 +1,33 @@
const webpack = require('webpack');
const path = require('path');
module.exports = {
mode: 'development',
target: 'node',
devtool: 'inline-source-map',
entry: {
main: './src/tsdb-kit/index.ts',
},
output: {
path: path.resolve(__dirname, './bin'),
filename: 'tsdb-kit.js'
},
plugins: [
new webpack.BannerPlugin({ banner: "#!/usr/bin/env node", raw: true }),
],
resolve: {
extensions: ['.ts', '.js'],
},
module: {
rules: [
{
test: /.ts$/,
loader: 'ts-loader',
options: {
configFile: 'bin.tsconfig.json'
}
}
]
}
};

650
yarn.lock

@ -279,6 +279,11 @@
exec-sh "^0.3.2"
minimist "^1.2.0"
"@discoveryjs/json-ext@^0.5.0":
version "0.5.7"
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
"@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
@ -466,6 +471,46 @@
"@types/yargs" "^15.0.0"
chalk "^4.0.0"
"@jridgewell/gen-mapping@^0.3.0":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
dependencies:
"@jridgewell/set-array" "^1.0.1"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/resolve-uri@^3.0.3":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
"@jridgewell/set-array@^1.0.1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
"@jridgewell/source-map@^0.3.2":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
dependencies:
"@jridgewell/gen-mapping" "^0.3.0"
"@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/sourcemap-codec@^1.4.10":
version "1.4.14"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
"@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.9":
version "0.3.15"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774"
integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==
dependencies:
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@sinonjs/commons@^1.7.0":
version "1.8.1"
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217"
@ -513,6 +558,32 @@
dependencies:
"@babel/types" "^7.3.0"
"@types/eslint-scope@^3.7.3":
version "3.7.4"
resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16"
integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==
dependencies:
"@types/eslint" "*"
"@types/estree" "*"
"@types/eslint@*":
version "8.4.5"
resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.5.tgz#acdfb7dd36b91cc5d812d7c093811a8f3d9b31e4"
integrity sha512-dhsC09y1gpJWnK+Ff4SGvCuSnk9DaU0BJZSzOwa6GVSg65XtTugLBITDAAzRU5duGBoXBHpdR/9jHGxJjNflJQ==
dependencies:
"@types/estree" "*"
"@types/json-schema" "*"
"@types/estree@*":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2"
integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==
"@types/estree@^0.0.51":
version "0.0.51"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40"
integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==
"@types/graceful-fs@^4.1.2":
version "4.1.4"
resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.4.tgz#4ff9f641a7c6d1a3508ff88bc3141b152772e753"
@ -547,6 +618,11 @@
jest-diff "^26.0.0"
pretty-format "^26.0.0"
"@types/json-schema@*", "@types/json-schema@^7.0.8":
version "7.0.11"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
"@types/lodash@^4.14.165":
version "4.14.165"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.165.tgz#74d55d947452e2de0742bad65270433b63a8c30f"
@ -584,6 +660,154 @@
dependencies:
"@types/yargs-parser" "*"
"@webassemblyjs/ast@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7"
integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==
dependencies:
"@webassemblyjs/helper-numbers" "1.11.1"
"@webassemblyjs/helper-wasm-bytecode" "1.11.1"
"@webassemblyjs/floating-point-hex-parser@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f"
integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==
"@webassemblyjs/helper-api-error@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16"
integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==
"@webassemblyjs/helper-buffer@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5"
integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==
"@webassemblyjs/helper-numbers@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae"
integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==
dependencies:
"@webassemblyjs/floating-point-hex-parser" "1.11.1"
"@webassemblyjs/helper-api-error" "1.11.1"
"@xtuc/long" "4.2.2"
"@webassemblyjs/helper-wasm-bytecode@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1"
integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==
"@webassemblyjs/helper-wasm-section@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a"
integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==
dependencies:
"@webassemblyjs/ast" "1.11.1"
"@webassemblyjs/helper-buffer" "1.11.1"
"@webassemblyjs/helper-wasm-bytecode" "1.11.1"
"@webassemblyjs/wasm-gen" "1.11.1"
"@webassemblyjs/ieee754@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614"
integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==
dependencies:
"@xtuc/ieee754" "^1.2.0"
"@webassemblyjs/leb128@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5"
integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==
dependencies:
"@xtuc/long" "4.2.2"
"@webassemblyjs/utf8@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff"
integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==
"@webassemblyjs/wasm-edit@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6"
integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==
dependencies:
"@webassemblyjs/ast" "1.11.1"
"@webassemblyjs/helper-buffer" "1.11.1"
"@webassemblyjs/helper-wasm-bytecode" "1.11.1"
"@webassemblyjs/helper-wasm-section" "1.11.1"
"@webassemblyjs/wasm-gen" "1.11.1"
"@webassemblyjs/wasm-opt" "1.11.1"
"@webassemblyjs/wasm-parser" "1.11.1"
"@webassemblyjs/wast-printer" "1.11.1"
"@webassemblyjs/wasm-gen@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76"
integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==
dependencies:
"@webassemblyjs/ast" "1.11.1"
"@webassemblyjs/helper-wasm-bytecode" "1.11.1"
"@webassemblyjs/ieee754" "1.11.1"
"@webassemblyjs/leb128" "1.11.1"
"@webassemblyjs/utf8" "1.11.1"
"@webassemblyjs/wasm-opt@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2"
integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==
dependencies:
"@webassemblyjs/ast" "1.11.1"
"@webassemblyjs/helper-buffer" "1.11.1"
"@webassemblyjs/wasm-gen" "1.11.1"
"@webassemblyjs/wasm-parser" "1.11.1"
"@webassemblyjs/wasm-parser@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199"
integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==
dependencies:
"@webassemblyjs/ast" "1.11.1"
"@webassemblyjs/helper-api-error" "1.11.1"
"@webassemblyjs/helper-wasm-bytecode" "1.11.1"
"@webassemblyjs/ieee754" "1.11.1"
"@webassemblyjs/leb128" "1.11.1"
"@webassemblyjs/utf8" "1.11.1"
"@webassemblyjs/wast-printer@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0"
integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==
dependencies:
"@webassemblyjs/ast" "1.11.1"
"@xtuc/long" "4.2.2"
"@webpack-cli/configtest@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.2.0.tgz#7b20ce1c12533912c3b217ea68262365fa29a6f5"
integrity sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==
"@webpack-cli/info@^1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.5.0.tgz#6c78c13c5874852d6e2dd17f08a41f3fe4c261b1"
integrity sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==
dependencies:
envinfo "^7.7.3"
"@webpack-cli/serve@^1.7.0":
version "1.7.0"
resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.7.0.tgz#e1993689ac42d2b16e9194376cfb6753f6254db1"
integrity sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==
"@xtuc/ieee754@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==
"@xtuc/long@4.2.2":
version "4.2.2"
resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
abab@^2.0.3:
version "2.0.5"
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a"
@ -597,6 +821,11 @@ acorn-globals@^6.0.0:
acorn "^7.1.1"
acorn-walk "^7.1.1"
acorn-import-assertions@^1.7.6:
version "1.8.0"
resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9"
integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==
acorn-walk@^7.1.1:
version "7.2.0"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
@ -607,7 +836,17 @@ acorn@^7.1.1:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
ajv@^6.12.3:
acorn@^8.5.0, acorn@^8.7.1:
version "8.8.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
ajv-keywords@^3.5.2:
version "3.5.2"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
ajv@^6.12.3, ajv@^6.12.5:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
@ -666,6 +905,11 @@ argparse@^1.0.7:
dependencies:
sprintf-js "~1.0.2"
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
arr-diff@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
@ -841,7 +1085,7 @@ braces@^2.3.1:
split-string "^3.0.2"
to-regex "^3.0.1"
braces@^3.0.1:
braces@^3.0.1, braces@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
@ -853,6 +1097,16 @@ browser-process-hrtime@^1.0.0:
resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626"
integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==
browserslist@^4.14.5:
version "4.21.3"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a"
integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==
dependencies:
caniuse-lite "^1.0.30001370"
electron-to-chromium "^1.4.202"
node-releases "^2.0.6"
update-browserslist-db "^1.0.5"
bs-logger@0.x:
version "0.2.6"
resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8"
@ -902,6 +1156,11 @@ camelcase@^6.0.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809"
integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
caniuse-lite@^1.0.30001370:
version "1.0.30001375"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001375.tgz#8e73bc3d1a4c800beb39f3163bf0190d7e5d7672"
integrity sha512-kWIMkNzLYxSvnjy0hL8w1NOaWNr2rn39RTAVyIwcw8juu60bZDWiF1/loOYANzjtJmy6qPgNmn38ro5Pygagdw==
capture-exit@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4"
@ -931,11 +1190,24 @@ chalk@^4.0.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
chalk@^4.1.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
char-regex@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
chrome-trace-event@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
ci-info@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
@ -965,6 +1237,15 @@ cliui@^6.0.0:
strip-ansi "^6.0.0"
wrap-ansi "^6.2.0"
clone-deep@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==
dependencies:
is-plain-object "^2.0.4"
kind-of "^6.0.2"
shallow-clone "^3.0.0"
co@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
@ -1007,6 +1288,11 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
colorette@^2.0.14:
version "2.0.19"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798"
integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==
combined-stream@^1.0.6, combined-stream@~1.0.6:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
@ -1014,6 +1300,16 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies:
delayed-stream "~1.0.0"
commander@^2.20.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
commander@^7.0.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
component-emitter@^1.2.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
@ -1052,7 +1348,7 @@ cross-spawn@^6.0.0:
shebang-command "^1.2.0"
which "^1.2.9"
cross-spawn@^7.0.0:
cross-spawn@^7.0.0, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
@ -1192,6 +1488,11 @@ ecc-jsbn@~0.1.1:
jsbn "~0.1.0"
safer-buffer "^2.1.0"
electron-to-chromium@^1.4.202:
version "1.4.217"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.217.tgz#f1f51b319435f4c1587a850806a0dfebe9774598"
integrity sha512-iX8GbAMij7cOtJPZo02CClpaPMWjvN5meqXiJXkBgwvraNWTNH0Z7F9tkznI34JRPtWASoPM/xWamq3oNb49GA==
emittery@^0.7.1:
version "0.7.2"
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82"
@ -1209,6 +1510,19 @@ end-of-stream@^1.1.0:
dependencies:
once "^1.4.0"
enhanced-resolve@^5.0.0, enhanced-resolve@^5.10.0:
version "5.10.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz#0dc579c3bb2a1032e357ac45b8f3a6f3ad4fb1e6"
integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==
dependencies:
graceful-fs "^4.2.4"
tapable "^2.2.0"
envinfo@^7.7.3:
version "7.8.1"
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475"
integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==
error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
@ -1216,6 +1530,16 @@ error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"
es-module-lexer@^0.9.0:
version "0.9.3"
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19"
integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
@ -1238,21 +1562,46 @@ escodegen@^1.14.1:
optionalDependencies:
source-map "~0.6.1"
eslint-scope@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
dependencies:
esrecurse "^4.3.0"
estraverse "^4.1.1"
esprima@^4.0.0, esprima@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
estraverse@^4.2.0:
esrecurse@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
dependencies:
estraverse "^5.2.0"
estraverse@^4.1.1, estraverse@^4.2.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
estraverse@^5.2.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
esutils@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
events@^3.2.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
exec-sh@^0.3.2:
version "0.3.4"
resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5"
@ -1375,6 +1724,11 @@ fast-levenshtein@~2.0.6:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
fastest-levenshtein@^1.0.12:
version "1.0.16"
resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5"
integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==
fb-watchman@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85"
@ -1496,6 +1850,11 @@ getpass@^0.1.1:
dependencies:
assert-plus "^1.0.0"
glob-to-regexp@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
@ -1513,6 +1872,11 @@ globals@^11.1.0:
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
graceful-fs@^4.1.2, graceful-fs@^4.2.9:
version "4.2.10"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
graceful-fs@^4.2.4:
version "4.2.4"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
@ -1648,6 +2012,11 @@ inherits@2:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
interpret@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9"
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip-regex@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
@ -1696,6 +2065,13 @@ is-core-module@^2.1.0:
dependencies:
has "^1.0.3"
is-core-module@^2.9.0:
version "2.10.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed"
integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==
dependencies:
has "^1.0.3"
is-data-descriptor@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
@ -2238,6 +2614,15 @@ jest-worker@^26.6.2:
merge-stream "^2.0.0"
supports-color "^7.0.0"
jest-worker@^27.4.5:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0"
integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==
dependencies:
"@types/node" "*"
merge-stream "^2.0.0"
supports-color "^8.0.0"
jest@^26.6.3:
version "26.6.3"
resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef"
@ -2302,7 +2687,7 @@ jsesc@^2.5.1:
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
json-parse-even-better-errors@^2.3.0:
json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
@ -2386,6 +2771,11 @@ lines-and-columns@^1.1.6:
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
loader-runner@^4.2.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1"
integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==
locate-path@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
@ -2408,6 +2798,13 @@ lodash@^4.17.19:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"
make-dir@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
@ -2463,6 +2860,14 @@ micromatch@^3.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.2"
micromatch@^4.0.0:
version "4.0.5"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
dependencies:
braces "^3.0.2"
picomatch "^2.3.1"
micromatch@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259"
@ -2476,6 +2881,11 @@ mime-db@1.44.0:
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mime-types@^2.1.12, mime-types@~2.1.19:
version "2.1.27"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
@ -2483,6 +2893,13 @@ mime-types@^2.1.12, mime-types@~2.1.19:
dependencies:
mime-db "1.44.0"
mime-types@^2.1.27:
version "2.1.35"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
dependencies:
mime-db "1.52.0"
mimic-fn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
@ -2550,6 +2967,11 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
neo-async@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
@ -2577,6 +2999,11 @@ node-notifier@^8.0.0:
uuid "^8.3.0"
which "^2.0.2"
node-releases@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
normalize-package-data@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
@ -2746,16 +3173,31 @@ path-parse@^1.0.6:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
path-parse@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
performance-now@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
picomatch@^2.0.4, picomatch@^2.0.5:
version "2.2.2"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
picomatch@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pirates@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87"
@ -2831,6 +3273,13 @@ querystring@0.2.0:
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
randombytes@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
dependencies:
safe-buffer "^5.1.0"
react-is@^17.0.1:
version "17.0.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339"
@ -2855,6 +3304,13 @@ read-pkg@^5.2.0:
parse-json "^5.0.0"
type-fest "^0.6.0"
rechoir@^0.7.0:
version "0.7.1"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686"
integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==
dependencies:
resolve "^1.9.0"
regex-not@^1.0.0, regex-not@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
@ -2955,6 +3411,15 @@ resolve@^1.10.0, resolve@^1.18.1, resolve@^1.3.2:
is-core-module "^2.1.0"
path-parse "^1.0.6"
resolve@^1.9.0:
version "1.22.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
dependencies:
is-core-module "^2.9.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
ret@~0.1.10:
version "0.1.15"
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
@ -2972,7 +3437,7 @@ rsvp@^4.8.4:
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==
safe-buffer@^5.0.1, safe-buffer@^5.1.2:
safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@ -3016,6 +3481,15 @@ saxes@^5.0.0:
dependencies:
xmlchars "^2.2.0"
schema-utils@^3.1.0, schema-utils@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281"
integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==
dependencies:
"@types/json-schema" "^7.0.8"
ajv "^6.12.5"
ajv-keywords "^3.5.2"
"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
@ -3031,6 +3505,20 @@ semver@^6.0.0, semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.3.4:
version "7.3.7"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
dependencies:
lru-cache "^6.0.0"
serialize-javascript@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8"
integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==
dependencies:
randombytes "^2.1.0"
set-blocking@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
@ -3046,6 +3534,13 @@ set-value@^2.0.0, set-value@^2.0.1:
is-plain-object "^2.0.3"
split-string "^3.0.1"
shallow-clone@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==
dependencies:
kind-of "^6.0.2"
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@ -3139,6 +3634,14 @@ source-map-support@^0.5.6:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map-support@~0.5.20:
version "0.5.21"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map-url@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
@ -3285,6 +3788,13 @@ supports-color@^7.0.0, supports-color@^7.1.0:
dependencies:
has-flag "^4.0.0"
supports-color@^8.0.0:
version "8.1.1"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
supports-hyperlinks@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz#f663df252af5f37c5d49bbd7eeefa9e0b9e59e47"
@ -3293,11 +3803,21 @@ supports-hyperlinks@^2.0.0:
has-flag "^4.0.0"
supports-color "^7.0.0"
supports-preserve-symlinks-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
symbol-tree@^3.2.4:
version "3.2.4"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
tapable@^2.1.1, tapable@^2.2.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
terminal-link@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994"
@ -3306,6 +3826,27 @@ terminal-link@^2.0.0:
ansi-escapes "^4.2.1"
supports-hyperlinks "^2.0.0"
terser-webpack-plugin@^5.1.3:
version "5.3.4"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.4.tgz#f4d31e265883d20fda3ca9c0fc6a53f173ae62e3"
integrity sha512-SmnkUhBxLDcBfTIeaq+ZqJXLVEyXxSaNcCeSezECdKjfkMrTTnPvapBILylYwyEvHFZAn2cJ8dtiXel5XnfOfQ==
dependencies:
"@jridgewell/trace-mapping" "^0.3.14"
jest-worker "^27.4.5"
schema-utils "^3.1.1"
serialize-javascript "^6.0.0"
terser "^5.14.1"
terser@^5.14.1:
version "5.14.2"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10"
integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==
dependencies:
"@jridgewell/source-map" "^0.3.2"
acorn "^8.5.0"
commander "^2.20.0"
source-map-support "~0.5.20"
test-exclude@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e"
@ -3403,6 +3944,16 @@ ts-jest@^26.4.4:
semver "7.x"
yargs-parser "20.x"
ts-loader@^9.3.1:
version "9.3.1"
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.3.1.tgz#fe25cca56e3e71c1087fe48dc67f4df8c59b22d4"
integrity sha512-OkyShkcZTsTwyS3Kt7a4rsT/t2qvEVQuKCTg4LJmpj9fhFR7ukGdZwV6Qq3tRUkqcXtfGpPR7+hFKHCG/0d3Lw==
dependencies:
chalk "^4.1.0"
enhanced-resolve "^5.0.0"
micromatch "^4.0.0"
semver "^7.3.4"
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
@ -3472,6 +4023,14 @@ unset-value@^1.0.0:
has-value "^0.3.1"
isobject "^3.0.0"
update-browserslist-db@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38"
integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==
dependencies:
escalade "^3.1.1"
picocolors "^1.0.0"
uri-js@^4.2.2:
version "4.4.0"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602"
@ -3554,6 +4113,14 @@ walker@^1.0.7, walker@~1.0.5:
dependencies:
makeerror "1.0.x"
watchpack@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==
dependencies:
glob-to-regexp "^0.4.1"
graceful-fs "^4.1.2"
webidl-conversions@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff"
@ -3564,6 +4131,67 @@ webidl-conversions@^6.1.0:
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514"
integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==
webpack-cli@^4.10.0:
version "4.10.0"
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.10.0.tgz#37c1d69c8d85214c5a65e589378f53aec64dab31"
integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==
dependencies:
"@discoveryjs/json-ext" "^0.5.0"
"@webpack-cli/configtest" "^1.2.0"
"@webpack-cli/info" "^1.5.0"
"@webpack-cli/serve" "^1.7.0"
colorette "^2.0.14"
commander "^7.0.0"
cross-spawn "^7.0.3"
fastest-levenshtein "^1.0.12"
import-local "^3.0.2"
interpret "^2.2.0"
rechoir "^0.7.0"
webpack-merge "^5.7.3"
webpack-merge@^5.7.3:
version "5.8.0"
resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61"
integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==
dependencies:
clone-deep "^4.0.1"
wildcard "^2.0.0"
webpack-sources@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
webpack@^5.74.0:
version "5.74.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.74.0.tgz#02a5dac19a17e0bb47093f2be67c695102a55980"
integrity sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==
dependencies:
"@types/eslint-scope" "^3.7.3"
"@types/estree" "^0.0.51"
"@webassemblyjs/ast" "1.11.1"
"@webassemblyjs/wasm-edit" "1.11.1"
"@webassemblyjs/wasm-parser" "1.11.1"
acorn "^8.7.1"
acorn-import-assertions "^1.7.6"
browserslist "^4.14.5"
chrome-trace-event "^1.0.2"
enhanced-resolve "^5.10.0"
es-module-lexer "^0.9.0"
eslint-scope "5.1.1"
events "^3.2.0"
glob-to-regexp "^0.4.1"
graceful-fs "^4.2.9"
json-parse-even-better-errors "^2.3.1"
loader-runner "^4.2.0"
mime-types "^2.1.27"
neo-async "^2.6.2"
schema-utils "^3.1.0"
tapable "^2.1.1"
terser-webpack-plugin "^5.1.3"
watchpack "^2.4.0"
webpack-sources "^3.2.3"
whatwg-encoding@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0"
@ -3604,6 +4232,11 @@ which@^2.0.1, which@^2.0.2:
dependencies:
isexe "^2.0.0"
wildcard@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec"
integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==
word-wrap@~1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
@ -3653,6 +4286,11 @@ y18n@^4.0.0:
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yargs-parser@20.x:
version "20.2.4"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"

Loading…
Cancel
Save