Merge pull request #3 from spotify/master

Updating fork
This commit is contained in:
Esteban Barrios
2020-08-28 14:30:10 +02:00
committed by GitHub
19 changed files with 289 additions and 127 deletions
-8
View File
@@ -33,19 +33,11 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: cache all node_modules
id: cache-modules
uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }}
- name: find location of global yarn cache
id: yarn-cache
if: steps.cache-modules.outputs.cache-hit != 'true'
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: cache global yarn cache
uses: actions/cache@v2
if: steps.cache-modules.outputs.cache-hit != 'true'
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}
-8
View File
@@ -25,19 +25,11 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: cache all node_modules
id: cache-modules
uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }}
- name: find location of global yarn cache
id: yarn-cache
if: steps.cache-modules.outputs.cache-hit != 'true'
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: cache global yarn cache
uses: actions/cache@v2
if: steps.cache-modules.outputs.cache-hit != 'true'
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}
+5
View File
@@ -61,6 +61,11 @@ catalog:
- https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/playback-lib-component.yaml
- https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/www-artist-component.yaml
- https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/shuffle-api-component.yaml
- https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml
- https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/template.yaml
- https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/create-react-app/template.yaml
- https://github.com/spotify/cookiecutter-golang/blob/master/template.yaml
- https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/docs-template/template.yaml
auth:
providers:
Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

+4
View File
@@ -101,3 +101,7 @@ more to come...
https://github.com/spotify/backstage/blob/master/packages/techdocs-container
[techdocs/cli]:
https://github.com/spotify/backstage/blob/master/packages/techdocs-cli
## TechDocs Big Picture
![TechDocs Big Picture](../..//assets/techdocs/techdocs_big_picture.png)
+2 -1
View File
@@ -39,6 +39,7 @@ import {
SidebarUserSettings,
SidebarThemeToggle,
SidebarPinButton,
DefaultProviderSettings,
} from '@backstage/core';
import { NavLink } from 'react-router-dom';
import { graphiQLRouteRef } from '@backstage/plugin-graphiql';
@@ -107,7 +108,7 @@ const Root: FC<{}> = ({ children }) => (
<SidebarSpace />
<SidebarDivider />
<SidebarThemeToggle />
<SidebarUserSettings />
<SidebarUserSettings providerSettings={<DefaultProviderSettings />} />
<SidebarPinButton />
</Sidebar>
{children}
+2
View File
@@ -37,11 +37,13 @@
"compression": "^1.7.4",
"cors": "^2.8.5",
"express": "^4.17.1",
"express-prom-bundle": "^6.1.0",
"express-promise-router": "^3.0.3",
"helmet": "^4.0.0",
"knex": "^0.21.1",
"lodash": "^4.17.15",
"morgan": "^1.10.0",
"prom-client": "^12.0.0",
"selfsigned": "^1.10.7",
"stoppable": "^1.1.0",
"winston": "^3.2.1"
@@ -37,6 +37,7 @@ import {
HttpsSettings,
} from './config';
import { createHttpServer, createHttpsServer } from './hostFactory';
import { metricsHandler } from './metrics';
const DEFAULT_PORT = 7000;
// '' is express default, which listens to all interfaces
@@ -48,6 +49,7 @@ export class ServiceBuilderImpl implements ServiceBuilder {
private logger: Logger | undefined;
private corsOptions: cors.CorsOptions | undefined;
private httpsSettings: HttpsSettings | undefined;
private enableMetrics: boolean = true;
private routers: [string, Router][];
// Reference to the module where builder is created - needed for hot module
// reloading
@@ -82,6 +84,9 @@ export class ServiceBuilderImpl implements ServiceBuilder {
this.httpsSettings = httpsSettings;
}
// For now, configuration of metrics is a simple boolean and active by default
this.enableMetrics = backendConfig.getOptionalBoolean('metrics') !== false;
return this;
}
@@ -131,6 +136,9 @@ export class ServiceBuilderImpl implements ServiceBuilder {
}
app.use(compression());
app.use(express.json());
if (this.enableMetrics) {
app.use(metricsHandler());
}
app.use(requestLoggingHandler());
for (const [root, route] of this.routers) {
app.use(root, route);
@@ -0,0 +1,37 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import prom from 'prom-client';
import promBundle from 'express-prom-bundle';
import { RequestHandler } from 'express';
/**
* Adds a /metrics endpoint, register default runtime metrics and instrument the router.
*/
export function metricsHandler(): RequestHandler {
// We can only initialize the metrics once and have to clean them up between hot reloads
prom.register.clear();
return promBundle({
includeMethod: true,
includePath: true,
// Using includePath alone is problematic, as it will include path labels with high
// cardinality (e.g. path params). Instead we would have to template them. However, this
// is difficult, as every backend plugin might use different routes. Instead we only take
// the first directory of the path, to have at least an idea how each plugin performs:
normalizePath: [['^/([^/]*)/.*', '/$1']],
promClient: { collectDefaultMetrics: {} },
});
}
@@ -0,0 +1,81 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
configApiRef,
githubAuthApiRef,
gitlabAuthApiRef,
googleAuthApiRef,
oauth2ApiRef,
oktaAuthApiRef,
microsoftAuthApiRef,
useApi,
} from '@backstage/core-api';
import Star from '@material-ui/icons/Star';
import React from 'react';
import { OAuthProviderSettings, OIDCProviderSettings } from './Settings';
export const DefaultProviderSettings = () => {
const configApi = useApi(configApiRef);
const providersConfig = configApi.getOptionalConfig('auth.providers');
const providers = providersConfig?.keys() ?? [];
return (
<>
{providers.includes('google') && (
<OIDCProviderSettings
title="Google"
apiRef={googleAuthApiRef}
icon={Star}
/>
)}
{providers.includes('microsoft') && (
<OIDCProviderSettings
title="Microsoft"
apiRef={microsoftAuthApiRef}
icon={Star}
/>
)}
{providers.includes('github') && (
<OAuthProviderSettings
title="Github"
apiRef={githubAuthApiRef}
icon={Star}
/>
)}
{providers.includes('gitlab') && (
<OAuthProviderSettings
title="Gitlab"
apiRef={gitlabAuthApiRef}
icon={Star}
/>
)}
{providers.includes('okta') && (
<OIDCProviderSettings
title="Okta"
apiRef={oktaAuthApiRef}
icon={Star}
/>
)}
{providers.includes('oauth2') && (
<OIDCProviderSettings
title="YourOrg"
apiRef={oauth2ApiRef}
icon={Star}
/>
)}
</>
);
};
@@ -23,10 +23,15 @@ import {
SidebarSearchField,
SidebarSpace,
SidebarUserSettings,
OAuthProviderSettings,
} from '.';
import HomeOutlinedIcon from '@material-ui/icons/HomeOutlined';
import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline';
import Star from '@material-ui/icons/Star';
import { MemoryRouter } from 'react-router-dom';
import {
githubAuthApiRef,
} from '@backstage/core-api';
export default {
title: 'Sidebar',
@@ -55,6 +60,12 @@ export const SampleSidebar = () => (
<SidebarIntro />
<SidebarSpace />
<SidebarDivider />
<SidebarUserSettings />
<SidebarUserSettings providerSettings={
<OAuthProviderSettings
title="Github"
apiRef={githubAuthApiRef}
icon={Star}
/>
} />
</Sidebar>
);
@@ -14,36 +14,22 @@
* limitations under the License.
*/
import {
githubAuthApiRef,
gitlabAuthApiRef,
googleAuthApiRef,
identityApiRef,
oauth2ApiRef,
oktaAuthApiRef,
microsoftAuthApiRef,
useApi,
configApiRef,
} from '@backstage/core-api';
import { identityApiRef, useApi } from '@backstage/core-api';
import Collapse from '@material-ui/core/Collapse';
import SignOutIcon from '@material-ui/icons/MeetingRoom';
import Star from '@material-ui/icons/Star';
import React, { useContext, useEffect } from 'react';
import { SidebarContext } from './config';
import { SidebarItem } from './Items';
import {
OAuthProviderSettings,
OIDCProviderSettings,
UserProfile as SidebarUserProfile,
} from './Settings';
import { UserProfile as SidebarUserProfile } from './Settings';
export function SidebarUserSettings() {
type SidebarUserSettingsProps = { providerSettings?: React.ReactNode };
export function SidebarUserSettings({
providerSettings,
}: SidebarUserSettingsProps) {
const { isOpen: sidebarOpen } = useContext(SidebarContext);
const [open, setOpen] = React.useState(false);
const identityApi = useApi(identityApiRef);
const configApi = useApi(configApiRef);
const providersConfig = configApi.getOptionalConfig('auth.providers');
const providers = providersConfig?.keys() ?? [];
// Close the provider list when sidebar collapse
useEffect(() => {
@@ -54,48 +40,8 @@ export function SidebarUserSettings() {
<>
<SidebarUserProfile open={open} setOpen={setOpen} />
<Collapse in={open} timeout="auto">
{providers.includes('google') && (
<OIDCProviderSettings
title="Google"
apiRef={googleAuthApiRef}
icon={Star}
/>
)}
{providers.includes('microsoft') && (
<OIDCProviderSettings
title="Microsoft"
apiRef={microsoftAuthApiRef}
icon={Star}
/>
)}
{providers.includes('github') && (
<OAuthProviderSettings
title="GitHub"
apiRef={githubAuthApiRef}
icon={Star}
/>
)}
{providers.includes('gitlab') && (
<OAuthProviderSettings
title="GitLab"
apiRef={gitlabAuthApiRef}
icon={Star}
/>
)}
{providers.includes('okta') && (
<OIDCProviderSettings
title="Okta"
apiRef={oktaAuthApiRef}
icon={Star}
/>
)}
{providers.includes('oauth2') && (
<OIDCProviderSettings
title="YourOrg"
apiRef={oauth2ApiRef}
icon={Star}
/>
)}
{providerSettings}
<SidebarItem
icon={SignOutIcon}
text="Sign Out"
@@ -34,4 +34,5 @@ export {
export type { SidebarContextType } from './config';
export { SidebarThemeToggle } from './SidebarThemeToggle';
export { SidebarUserSettings } from './UserSettings';
export { DefaultProviderSettings } from './DefaultProviderSettings';
export * from './Settings';
@@ -13,6 +13,28 @@ backend:
origin: http://localhost:3000
methods: [GET, POST, PUT, DELETE]
credentials: true
{{#if dbTypeSqlite}}
database:
client: sqlite3
connection: ':memory:'
{{/if}}
{{#if dbTypePG}}
database:
client: pg
connection:
host:
$secret:
env: POSTGRES_HOST
port:
$secret:
env: POSTGRES_PORT
user:
$secret:
env: POSTGRES_USER
password:
$secret:
env: POSTGRES_PASSWORD
{{/if}}
proxy:
'/test':
@@ -27,7 +49,7 @@ auth:
catalog:
locations:
# Backstage Example Component
# Backstage example components
- type: github
target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/artist-lookup-component.yaml
- type: github
@@ -44,8 +66,7 @@ catalog:
target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/www-artist-component.yaml
- type: github
target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/shuffle-api-component.yaml
# Backstage Example Templates
# Backstage example templates
- type: github
target: https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml
- type: github
@@ -9,6 +9,7 @@ import {
SidebarUserSettings,
SidebarThemeToggle,
SidebarPinButton,
DefaultProviderSettings,
} from '@backstage/core';
export const AppSidebar = () => (
@@ -22,7 +23,7 @@ export const AppSidebar = () => (
<SidebarSpace />
<SidebarDivider />
<SidebarThemeToggle />
<SidebarUserSettings />
<SidebarUserSettings providerSettings={<DefaultProviderSettings />} />
<SidebarPinButton />
</Sidebar>
);
@@ -7,18 +7,13 @@
*/
import {
createDatabase,
createServiceBuilder,
loadBackendConfig,
getRootLogger,
useHotMemoize,
} from '@backstage/backend-common';
import { ConfigReader, AppConfig } from '@backstage/config';
{{#if dbTypePG}}
import knex, { PgConnectionConfig } from 'knex';
{{/if}}
{{#if dbTypeSqlite}}
import knex from 'knex';
{{/if}}
import auth from './plugins/auth';
import catalog from './plugins/catalog';
import identity from './plugins/identity';
@@ -32,30 +27,10 @@ function makeCreateEnv(loadedConfigs: AppConfig[]) {
return (plugin: string): PluginEnvironment => {
const logger = getRootLogger().child({ type: 'plugin', plugin });
{{#if dbTypePG}}
const knexConfig = {
client: 'pg',
useNullAsDefault: true,
const database = createDatabase(config.getConfig('backend.database'), {
connection: {
port: process.env.POSTGRES_PORT,
host: process.env.POSTGRES_HOST,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
database: `backstage_plugin_${plugin}`,
} as PgConnectionConfig,
};
{{/if}}
{{#if dbTypeSqlite}}
const knexConfig = {
client: 'sqlite3',
connection: ':memory:',
useNullAsDefault: true,
};
{{/if}}
const database = knex(knexConfig);
database.client.pool.on('createSuccess', (_eventId: any, resource: any) => {
resource.run('PRAGMA foreign_keys = ON', () => {});
},
});
return { logger, database, config };
};
@@ -15,7 +15,7 @@
*/
import React, { useEffect } from 'react';
import { useWorkflowRuns } from '../useWorkflowRuns';
import { WorkflowRun } from '../WorkflowRunsTable';
import { WorkflowRun, WorkflowRunsTable } from '../WorkflowRunsTable';
import { Entity } from '@backstage/catalog-model';
import { WorkflowRunStatus } from '../WorkflowRunStatus';
import {
@@ -108,3 +108,51 @@ export const Widget = ({
</InfoCard>
);
};
const RecentWorkflowRunsCardContent = ({
error,
loading,
branch,
}: {
error?: Error;
loading?: boolean;
branch: string;
}) => {
if (error) return <Typography>Couldn't fetch {branch} runs</Typography>;
if (loading) return <LinearProgress />;
return <WorkflowRunsTable />;
};
export const RecentWorkflowRunsCard = ({
entity,
branch = 'master',
}: {
entity: Entity;
branch: string;
}) => {
const errorApi = useApi(errorApiRef);
const [owner, repo] = (
entity?.metadata.annotations?.['backstage.io/github-actions-id'] ?? '/'
).split('/');
const [{ loading, error }] = useWorkflowRuns({
owner,
repo,
branch,
});
useEffect(() => {
if (error) {
errorApi.post(error);
}
}, [error, errorApi]);
return (
<InfoCard title={`${branch} builds`}>
<RecentWorkflowRunsCardContent
error={error}
loading={loading}
branch={branch}
/>
</InfoCard>
);
};
@@ -13,4 +13,4 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { Widget } from './Widget';
export { Widget, RecentWorkflowRunsCard } from './Widget';
+49 -12
View File
@@ -6511,6 +6511,11 @@ bindings@^1.5.0:
dependencies:
file-uri-to-path "1.0.0"
bintrees@1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524"
integrity sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=
bl@^1.0.0:
version "1.2.2"
resolved "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c"
@@ -7389,6 +7394,11 @@ cli-width@^2.0.0:
resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
cli-width@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
clipboard@^2.0.0:
version "2.0.6"
resolved "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz#52921296eec0fdf77ead1749421b21c968647376"
@@ -10135,6 +10145,14 @@ expect@^26.0.1:
jest-message-util "^26.0.1"
jest-regex-util "^26.0.0"
express-prom-bundle@^6.1.0:
version "6.1.0"
resolved "https://registry.npmjs.org/express-prom-bundle/-/express-prom-bundle-6.1.0.tgz#8fd72e5bedbbd686b8e7c49e0aecbc1b14b28743"
integrity sha512-krlvp5r6sgJ1IwL6M6/coMrNbAlwtpk+uyivfeyRMCupTK4HzIEQHH0gwrNhLiKyPmSbtZcSmtO6s+PRumRp5g==
dependencies:
on-finished "^2.3.0"
url-value-parser "^2.0.0"
express-promise-router@^3.0.3:
version "3.0.3"
resolved "https://registry.npmjs.org/express-promise-router/-/express-promise-router-3.0.3.tgz#5e6d22a5a3f013d71833172fe8d7ab780c3f6b70"
@@ -12505,20 +12523,20 @@ inquirer@^6.2.0:
through "^2.3.6"
inquirer@^7.0.0, inquirer@^7.0.4:
version "7.2.0"
resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.2.0.tgz#63ce99d823090de7eb420e4bb05e6f3449aa389a"
integrity sha512-E0c4rPwr9ByePfNlTIB8z51kK1s2n6jrHuJeEHENl/sbq2G/S1auvibgEwNR4uSyiU+PiYHqSwsgGiXjG8p5ZQ==
version "7.3.3"
resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003"
integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==
dependencies:
ansi-escapes "^4.2.1"
chalk "^3.0.0"
chalk "^4.1.0"
cli-cursor "^3.1.0"
cli-width "^2.0.0"
cli-width "^3.0.0"
external-editor "^3.0.3"
figures "^3.0.0"
lodash "^4.17.15"
lodash "^4.17.19"
mute-stream "0.0.8"
run-async "^2.4.0"
rxjs "^6.5.3"
rxjs "^6.6.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
through "^2.3.6"
@@ -16227,7 +16245,7 @@ omggif@1.0.7:
resolved "https://registry.npmjs.org/omggif/-/omggif-1.0.7.tgz#59d2eecb0263de84635b3feb887c0c9973f1e49d"
integrity sha1-WdLuywJj3oRjWz/riHwMmXPx5J0=
on-finished@~2.3.0:
on-finished@^2.3.0, on-finished@~2.3.0:
version "2.3.0"
resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
@@ -17809,6 +17827,13 @@ progress@^2.0.0:
resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
prom-client@^12.0.0:
version "12.0.0"
resolved "https://registry.npmjs.org/prom-client/-/prom-client-12.0.0.tgz#9689379b19bd3f6ab88a9866124db9da3d76c6ed"
integrity sha512-JbzzHnw0VDwCvoqf8y1WDtq4wSBAbthMB1pcVI/0lzdqHGJI3KBJDXle70XK+c7Iv93Gihqo0a5LlOn+g8+DrQ==
dependencies:
tdigest "^0.1.1"
promise-inflight@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
@@ -19538,10 +19563,10 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
rxjs@^6.3.3, rxjs@^6.4.0, rxjs@^6.5.2, rxjs@^6.5.3, rxjs@^6.5.5:
version "6.6.0"
resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.0.tgz#af2901eedf02e3a83ffa7f886240ff9018bbec84"
integrity sha512-3HMA8z/Oz61DUHe+SdOiQyzIf4tOx5oQHmMir7IZEu6TMqCLHT4LRcmNaUS0NwOz8VLvmmBduMsoaUvMaIiqzg==
rxjs@^6.3.3, rxjs@^6.4.0, rxjs@^6.5.2, rxjs@^6.5.3, rxjs@^6.5.5, rxjs@^6.6.0:
version "6.6.2"
resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz#8096a7ac03f2cc4fe5860ef6e572810d9e01c0d2"
integrity sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==
dependencies:
tslib "^1.9.0"
@@ -21142,6 +21167,13 @@ tcp-port-used@^1.0.1:
debug "4.1.0"
is2 "2.0.1"
tdigest@^0.1.1:
version "0.1.1"
resolved "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz#2e3cb2c39ea449e55d1e6cd91117accca4588021"
integrity sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=
dependencies:
bintrees "1.0.1"
telejson@^3.2.0:
version "3.3.0"
resolved "https://registry.npmjs.org/telejson/-/telejson-3.3.0.tgz#6d814f3c0d254d5c4770085aad063e266b56ad03"
@@ -22131,6 +22163,11 @@ url-to-options@^1.0.1:
resolved "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9"
integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=
url-value-parser@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/url-value-parser/-/url-value-parser-2.0.1.tgz#c8179a095ab9ec1f5aa17ca36af5af396b4e95ed"
integrity sha512-bexECeREBIueboLGM3Y1WaAzQkIn+Tca/Xjmjmfd0S/hFHSCEoFkNh0/D0l9G4K74MkEP/lLFRlYnxX3d68Qgw==
url@^0.11.0, url@~0.11.0:
version "0.11.0"
resolved "https://registry.npmjs.org/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"