diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 548a4cd212..307f28964d 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [12.x, 14.x] + node-version: [14.x] steps: - uses: actions/checkout@v3 - name: Setup Node.js ${{ matrix.node-version }} diff --git a/backend/package-lock.json b/backend/package-lock.json index ee8f7a3ebc..66a4defb1b 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1803,6 +1803,12 @@ "eslint-config-esnext": "^4.1.0" }, "dependencies": { + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, "eslint": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", @@ -1936,12 +1942,12 @@ } }, "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "requires": { - "minimist": "^1.2.6" + "minimist": "^1.2.5" } }, "optionator": { @@ -1985,6 +1991,29 @@ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + } + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -2945,9 +2974,9 @@ "dev": true }, "got": { - "version": "11.8.5", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", - "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", + "version": "11.8.3", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", + "integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==", "requires": { "@sindresorhus/is": "^4.0.0", "@szmarczak/http-timer": "^4.0.5", @@ -3453,9 +3482,9 @@ "dev": true }, "jose": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.6.tgz", - "integrity": "sha512-FVoPY7SflDodE4lknJmbAHSUjLCzE2H1F6MS0RYKMQ8SR+lNccpMf8R4eqkNYyyUjR5qZReOzZo5C5YiHOCjjg==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.5.tgz", + "integrity": "sha512-BAiDNeDKTMgk4tvD0BbxJ8xHEHBZgpeRZ1zGPPsitSyMgjoMWiLGYAE7H7NpP5h0lPppQajQs871E8NHUrzVPA==", "requires": { "@panva/asn1.js": "^1.0.0" } diff --git a/backend/package.json b/backend/package.json index 60a908efab..1da26a1eff 100644 --- a/backend/package.json +++ b/backend/package.json @@ -19,8 +19,8 @@ "main": "src/server.ts", "scripts": { "start": "npm run tsc && NODE_ENV=production node ./dist/server.js --log=1 --registry=localhost:50051", - "start:dev": "export NODE_ENV=development && nodemon src/server.ts --log=1 --registry=localhost:50051", - "debug": "npm run tsc && export NODE_ENV=development && node --inspect ./dist/server.js --log=1 --registry=localhost:50051", + "start:dev": "export NODE_TLS_REJECT_UNAUTHORIZED=0 && export NODE_ENV=development && nodemon src/server.ts --log=1 --registry=localhost:50051", + "debug": "npm run tsc && export NODE_TLS_REJECT_UNAUTHORIZED=0 && export NODE_ENV=development && node --inspect ./dist/server.js --log=1 --registry=localhost:50051", "build-only": "tsc -p . && node ./dist/server.js --log=1 --registry=localhost:50051 --buildonly", "build": "npm run build:clean; npm run tsc", "build:clean": "rimraf ./dist", diff --git a/backend/src/routes/api/cluster-settings/clusterSettingsUtils.ts b/backend/src/routes/api/cluster-settings/clusterSettingsUtils.ts index 9f02fef637..78ac14852f 100644 --- a/backend/src/routes/api/cluster-settings/clusterSettingsUtils.ts +++ b/backend/src/routes/api/cluster-settings/clusterSettingsUtils.ts @@ -71,6 +71,9 @@ export const updateClusterSettings = async ( kind: 'ConfigMap', metadata: { name: 'notebook-controller-culler-config', + labels: { + 'opendatahub.io/dashboard': 'true', + }, }, data: { ENABLE_CULLING: String(isEnabled), diff --git a/backend/src/routes/api/gpu/index.ts b/backend/src/routes/api/gpu/index.ts index 5f37bc31aa..c781ccfcb8 100644 --- a/backend/src/routes/api/gpu/index.ts +++ b/backend/src/routes/api/gpu/index.ts @@ -1,12 +1,8 @@ import { KubeFastifyInstance } from '../../../types'; import { getGPUNumber } from './gpuUtils'; -import { secureRoute } from '../../../utils/route-security'; export default async (fastify: KubeFastifyInstance): Promise => { - fastify.get( - '/', - secureRoute(fastify)(async () => { - return getGPUNumber(fastify); - }), - ); + fastify.get('/', async () => { + return getGPUNumber(fastify); + }); }; diff --git a/backend/src/routes/api/images/imageUtils.ts b/backend/src/routes/api/images/imageUtils.ts index d544958931..960e728f99 100644 --- a/backend/src/routes/api/images/imageUtils.ts +++ b/backend/src/routes/api/images/imageUtils.ts @@ -211,6 +211,7 @@ export const postImage = async ( const labels = { 'app.kubernetes.io/created-by': 'byon', 'opendatahub.io/notebook-image': 'true', + 'opendatahub.io/dashboard': 'true', }; const imageStreams = (await getImageStreams(fastify, labels)) as ImageStream[]; const validName = imageStreams.filter((is) => is.metadata.name === body.name); diff --git a/backend/src/routes/api/k8s/index.ts b/backend/src/routes/api/k8s/index.ts new file mode 100644 index 0000000000..69c6816d0f --- /dev/null +++ b/backend/src/routes/api/k8s/index.ts @@ -0,0 +1,46 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { KubeFastifyInstance } from '../../../types'; +import { USER_ACCESS_TOKEN } from '../../../utils/constants'; +import { passThrough } from './pass-through'; + +module.exports = async (fastify: KubeFastifyInstance) => { + const kc = fastify.kube.config; + const cluster = kc.getCurrentCluster(); + + /** + * Pass through API for all things kubernetes + * Acts on the user who made the call -- does not need route security; k8s provides that. + */ + fastify.route({ + method: ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT', 'OPTIONS'], + url: '/*', + handler: ( + req: FastifyRequest<{ + Querystring: Record; + Params: { '*': string; [key: string]: string }; + Body: { [key: string]: unknown }; + Headers: { [USER_ACCESS_TOKEN]: string }; + }>, + reply: FastifyReply, + ) => { + const data = JSON.stringify(req.body); + const kubeUri = req.params['*']; + let url = `${cluster.server}/${kubeUri}`; + + // Apply query params + const query = req.query; + if (Object.keys(query)) { + url += `?${Object.keys(query) + .map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(query[k])}`) + .join('&')}`; + } + + return passThrough(fastify, req, { url, method: req.method, requestData: data }).catch( + ({ code, response }) => { + reply.code(code); + reply.send(response); + }, + ); + }, + }); +}; diff --git a/backend/src/routes/api/k8s/pass-through.ts b/backend/src/routes/api/k8s/pass-through.ts new file mode 100644 index 0000000000..bb0d241e1b --- /dev/null +++ b/backend/src/routes/api/k8s/pass-through.ts @@ -0,0 +1,117 @@ +import { FastifyRequest } from 'fastify'; +import https, { RequestOptions } from 'https'; +import { K8sResourceCommon, K8sStatus, KubeFastifyInstance } from '../../../types'; +import { DEV_MODE, USER_ACCESS_TOKEN } from '../../../utils/constants'; +import { getDirectCallOptions } from '../../../utils/directCallUtils'; + +type PassThroughData = { + method: string; + requestData: string; + url: string; +}; + +const isK8sStatus = (data: Record): data is K8sStatus => data.kind === 'Status'; + +const setupRequest = async ( + fastify: KubeFastifyInstance, + request: FastifyRequest<{ Headers: { [USER_ACCESS_TOKEN]: string } }>, + data: PassThroughData, +): Promise<{ url: string; requestOptions: RequestOptions }> => { + const { method, url } = data; + + // TODO: Remove when bug is fixed - https://issues.redhat.com/browse/HAC-1825 + let safeURL = url; + if (method.toLowerCase() === 'post') { + // Core SDK builds the wrong path for k8s -- can't post to a resource name; remove the name from the url + // eg: POST /.../configmaps/my-config-map => POST /.../configmaps + const urlParts = url.split('/'); + urlParts.pop(); + safeURL = urlParts.join('/'); + } + + const requestOptions = await getDirectCallOptions(fastify, request, url); + + return { + url: safeURL, + requestOptions: { + ...requestOptions, + method, + }, + }; +}; + +export const passThrough = ( + fastify: KubeFastifyInstance, + request: FastifyRequest<{ Headers: { [USER_ACCESS_TOKEN]: string } }>, + data: PassThroughData, +): Promise => { + const { method, requestData } = data; + + return new Promise((resolve, reject) => { + setupRequest(fastify, request, data).then(({ url, requestOptions }) => { + if (requestData) { + requestOptions.headers = { + ...requestOptions.headers, + 'Content-Type': `application/${ + method === 'PATCH' ? 'json-patch+json' : 'json' + };charset=UTF-8`, + 'Content-Length': requestData.length, + }; + } + + fastify.log.info(`Making API ${method} request to ${url}`); + + const httpsRequest = https + .request(url, requestOptions, (res) => { + let data = ''; + res + .setEncoding('utf8') + .on('data', (chunk) => { + data += chunk; + }) + .on('end', () => { + let parsedData: K8sResourceCommon | K8sStatus; + try { + parsedData = JSON.parse(data); + } catch (e) { + // Likely not JSON, print the error and return the content to the client + fastify.log.error(`Parsing response error: ${e}, ${data}`); + reject({ code: 500, response: data }); + return; + } + + if (isK8sStatus(parsedData)) { + if (parsedData.status !== 'Success') { + fastify.log.warn( + `Unsuccessful status Object, ${ + DEV_MODE ? JSON.stringify(parsedData, null, 2) : JSON.stringify(parsedData) + }`, + ); + reject({ code: parsedData.code, response: parsedData }); + return; + } + } + + fastify.log.info('Successful request, returning data to caller.'); + resolve(parsedData); + }) + .on('error', (error) => { + if (error) { + fastify.log.error(`Kube parsing response error: ${error}`); + reject({ code: 500, response: error }); + } + }); + }) + .on('error', (error) => { + fastify.log.error(`Kube request error: ${error}`); + reject({ code: 500, response: error }); + }); + + if (requestData) { + httpsRequest.write(requestData); + } + + httpsRequest.end(); + }); + }); +}; diff --git a/backend/src/routes/api/prometheus/index.ts b/backend/src/routes/api/prometheus/index.ts new file mode 100644 index 0000000000..3d3131ef75 --- /dev/null +++ b/backend/src/routes/api/prometheus/index.ts @@ -0,0 +1,19 @@ +import { KubeFastifyInstance, OauthFastifyRequest, PrometheusResponse } from '../../../types'; +import { callPrometheus } from '../../../utils/prometheusUtils'; + +module.exports = async (fastify: KubeFastifyInstance) => { + /** + * Pass through API for getting information out of prometheus. + * Acts on the user who made the call -- does not need route security; k8s provides that. + */ + fastify.post( + '/', + async ( + request: OauthFastifyRequest<{ Body: { query: string; namespace: string } }>, + ): Promise<{ code: number; response: PrometheusResponse }> => { + const { query, namespace } = request.body; + + return callPrometheus(fastify, request, query, namespace); + }, + ); +}; diff --git a/backend/src/routes/api/status/statusUtils.ts b/backend/src/routes/api/status/statusUtils.ts index 0c62463b9b..8db60677a4 100644 --- a/backend/src/routes/api/status/statusUtils.ts +++ b/backend/src/routes/api/status/statusUtils.ts @@ -9,7 +9,9 @@ export const status = async ( request: FastifyRequest, ): Promise<{ kube: KubeStatus }> => { const kubeContext = fastify.kube.currentContext; - const { currentContext, namespace, currentUser, clusterID, clusterBranding } = fastify.kube; + const { config, currentContext, namespace, currentUser, clusterID, clusterBranding } = + fastify.kube; + const { server } = config.getCurrentCluster(); const userName = await getUserName(fastify, request); const isAdmin = await isUserAdmin(fastify, userName, namespace); @@ -33,6 +35,7 @@ export const status = async ( clusterBranding, isAdmin, isAllowed, + serverURL: server, }, }; } diff --git a/backend/src/routes/api/validate-isv/validateISV.ts b/backend/src/routes/api/validate-isv/validateISV.ts index 2fe084df7c..d7cfc1a8d1 100644 --- a/backend/src/routes/api/validate-isv/validateISV.ts +++ b/backend/src/routes/api/validate-isv/validateISV.ts @@ -58,7 +58,13 @@ export const createAccessSecret = async ( const name = enable.validationSecret; const secret = { apiVersion: 'v1', - metadata: { name, namespace }, + metadata: { + name, + namespace, + labels: { + 'opendatahub.io/dashboard': 'true', + }, + }, type: 'Opaque', stringData, }; @@ -151,6 +157,9 @@ export const runValidation = async ( annotations: { 'cronjob.kubernetes.io/instantiate': 'manual', }, + labels: { + 'opendatahub.io/dashboard': 'true', + }, }, spec: cronJob.spec.jobTemplate.spec, }; diff --git a/backend/src/types.ts b/backend/src/types.ts index 18186f48fc..9da2c5747f 100644 --- a/backend/src/types.ts +++ b/backend/src/types.ts @@ -16,6 +16,7 @@ export type DashboardConfig = K8sResourceCommon & { disableISVBadges: boolean; disableAppLauncher: boolean; disableUserManagement: boolean; + disableProjects: boolean; }; groupsConfig?: { adminGroups: string; @@ -100,6 +101,18 @@ export type K8sResourceCommon = { }; } & K8sResourceBase; +/** + * A status object when Kube backend can't handle a request. + */ +export type K8sStatus = { + kind: string; + apiVersion: string; + code: number; + message: string; + reason: string; + status: string; +}; + export enum BUILD_PHASE { none = 'Not started', new = 'New', @@ -185,6 +198,7 @@ export type KubeStatus = { clusterBranding: string; isAdmin: boolean; isAllowed: boolean; + serverURL: string; }; export type KubeDecorator = KubeStatus & { @@ -457,37 +471,6 @@ export type BYONImagePackage = { visible: boolean; }; -export type PipelineRunKind = { - spec: { - params: { - name: string; - value: string; - }[]; - pipelineRef: { - name: string; - }; - workspaces?: [ - { - name: string; - volumeClaimTemplate: { - spec: { - accessModes: string[]; - resources: { - requests: { - storage: string; - }; - }; - }; - }; - }, - ]; - }; -} & K8sResourceCommon; - -export type PipelineRunListKind = { - items: PipelineRunKind[]; -} & K8sResourceBase; - export type ImageStreamTag = { name: string; labels?: { [key: string]: string }; diff --git a/backend/src/utils/constants.ts b/backend/src/utils/constants.ts index aaad7ca522..69c758e6fa 100644 --- a/backend/src/utils/constants.ts +++ b/backend/src/utils/constants.ts @@ -7,6 +7,8 @@ export const LOG_LEVEL = process.env.FASTIFY_LOG_LEVEL || process.env.LOG_LEVEL export const DEV_MODE = process.env.APP_ENV === 'development'; export const APP_ENV = process.env.APP_ENV; +export const USER_ACCESS_TOKEN = 'x-forwarded-access-token'; + export const yamlRegExp = /\.ya?ml$/; export const mdRegExp = /\.md$/; @@ -25,6 +27,9 @@ export const blankDashboardCR: DashboardConfig = { kind: 'OdhDashboardConfig', metadata: { name: 'odh-dashboard-config', + labels: { + 'opendatahub.io/dashboard': 'true', + }, }, spec: { dashboardConfig: { @@ -37,6 +42,7 @@ export const blankDashboardCR: DashboardConfig = { disableISVBadges: false, disableAppLauncher: false, disableUserManagement: false, + disableProjects: false, }, notebookController: { enabled: true, diff --git a/backend/src/utils/deployment.ts b/backend/src/utils/deployment.ts index 12010ec8c8..cc5b4ff54e 100644 --- a/backend/src/utils/deployment.ts +++ b/backend/src/utils/deployment.ts @@ -40,6 +40,9 @@ export const rolloutDeployment = async ( annotations: { 'kubectl.kubernetes.io/restartedAt': new Date().toISOString(), }, + labels: { + 'opendatahub.io/dashboard': 'true', + }, }, }, }, diff --git a/backend/src/utils/directCallUtils.ts b/backend/src/utils/directCallUtils.ts new file mode 100644 index 0000000000..0976dea887 --- /dev/null +++ b/backend/src/utils/directCallUtils.ts @@ -0,0 +1,40 @@ +import { RequestOptions } from 'https'; +import { DEV_MODE, USER_ACCESS_TOKEN } from './constants'; +import { KubeFastifyInstance, OauthFastifyRequest } from '../types'; + +export const getDirectCallOptions = async ( + fastify: KubeFastifyInstance, + request: OauthFastifyRequest, + url: string, +): Promise => { + // Use our kube setup to boostrap our request + const kc = fastify.kube.config; + const kubeOptions: Parameters[0] = { url }; + await kc.applyToRequest(kubeOptions); + const { headers: kubeHeaders, ca } = kubeOptions; + + // Adjust the header auth token + let headers; + if (DEV_MODE) { + // In dev mode, we always are logged in fully -- no service accounts + headers = kubeHeaders; + } else { + // When not in dev mode, we want to switch the token from the service account to the user + const accessToken = request.headers[USER_ACCESS_TOKEN]; + if (!accessToken) { + fastify.log.error( + `No ${USER_ACCESS_TOKEN} header. Cannot make a pass through call as this user.`, + ); + throw new Error('No access token provided by oauth. Cannot make any API calls to kube.'); + } + headers = { + ...kubeHeaders, + Authorization: `Bearer ${accessToken}`, + }; + } + + return { + ca, + headers, + }; +}; diff --git a/backend/src/utils/envUtils.ts b/backend/src/utils/envUtils.ts index ba6f11e9ed..51dac24919 100644 --- a/backend/src/utils/envUtils.ts +++ b/backend/src/utils/envUtils.ts @@ -135,6 +135,9 @@ const generateSecret = ( metadata: { name, namespace, + labels: { + 'opendatahub.io/dashboard': 'true', + }, }, stringData: secrets, type: 'Opaque', @@ -152,6 +155,9 @@ const generateConfigMap = ( metadata: { name, namespace, + labels: { + 'opendatahub.io/dashboard': 'true', + }, }, data: configmap, }; diff --git a/backend/src/utils/notebookUtils.ts b/backend/src/utils/notebookUtils.ts index df36ceb960..370f5bc79a 100644 --- a/backend/src/utils/notebookUtils.ts +++ b/backend/src/utils/notebookUtils.ts @@ -79,6 +79,9 @@ export const createRBAC = async ( kind: 'Role', metadata: { name: `${notebookData.metadata.name}-notebook-view`, + labels: { + 'opendatahub.io/dashboard': 'true', + }, }, rules: [ { @@ -95,6 +98,9 @@ export const createRBAC = async ( kind: 'RoleBinding', metadata: { name: `${notebookData.metadata.name}-notebook-view`, + labels: { + 'opendatahub.io/dashboard': 'true', + }, }, roleRef: { apiGroup: 'rbac.authorization.k8s.io', @@ -252,6 +258,7 @@ export const assembleNotebook = async ( app: name, 'opendatahub.io/odh-managed': 'true', 'opendatahub.io/user': translatedUsername, + 'opendatahub.io/dashboard': 'true', }, annotations: { 'notebooks.opendatahub.io/oauth-logout-url': `${url}/notebookController/${translatedUsername}/home`, @@ -609,6 +616,9 @@ const assemblePvc = ( metadata: { name: pvcName, namespace, + labels: { + 'opendatahub.io/dashboard': 'true', + }, }, spec: { accessModes: ['ReadWriteOnce'], diff --git a/backend/src/utils/prometheusUtils.ts b/backend/src/utils/prometheusUtils.ts new file mode 100644 index 0000000000..6c0f2822d5 --- /dev/null +++ b/backend/src/utils/prometheusUtils.ts @@ -0,0 +1,56 @@ +import { KubeFastifyInstance, OauthFastifyRequest, PrometheusResponse } from '../types'; +import https from 'https'; +import { getDirectCallOptions } from './directCallUtils'; +import { DEV_MODE } from './constants'; + +export const callPrometheus = async ( + fastify: KubeFastifyInstance, + request: OauthFastifyRequest, + query: string, + namespace: string, +): Promise<{ code: number; response: PrometheusResponse }> => { + if (!query) { + fastify.log.warn('Prometheus call was made without a query'); + return Promise.reject({ code: 400, response: 'Failed to provide a query' }); + } + + // Use a local path to the thanos querier; only works on-cluster + let host = `https://thanos-querier.openshift-monitoring.svc.cluster.local:9091`; + if (DEV_MODE) { + const apiPath = fastify.kube.config.getCurrentCluster().server; + const namedHost = apiPath.slice('https://api.'.length).split(':')[0]; + host = `https://thanos-querier-openshift-monitoring.apps.${namedHost}`; + } + + const url = `${host}/api/v1/query?namespace=${namespace}&query=${query}`; + const options = await getDirectCallOptions(fastify, request, url); + + return new Promise((resolve, reject) => { + fastify.log.info(`Making Prometheus call: ${url}`); + fastify.log.info(`Prometheus query: ${query}`); + + const httpsRequest = https + .get(url, options, (res) => { + res.setEncoding('utf8'); + let rawData = ''; + res.on('data', (chunk: any) => { + rawData += chunk; + }); + res.on('end', () => { + try { + const parsedData: PrometheusResponse = JSON.parse(rawData); + fastify.log.info('Successful response from Prometheus.'); + resolve({ code: 200, response: parsedData }); + } catch (e) { + fastify.log.error(`Failure parsing the response from Prometheus. ${e.message || e}`); + reject({ code: 500, response: rawData }); + } + }); + }) + .on('error', (e) => { + fastify.log.error(`Failure calling Prometheus. ${e.message}`); + reject({ code: 500, response: `Cannot fetch prometheus data, ${e.message}` }); + }); + httpsRequest.end(); + }); +}; diff --git a/backend/src/utils/userUtils.ts b/backend/src/utils/userUtils.ts index 6a8a1e7ab6..e04204e9da 100644 --- a/backend/src/utils/userUtils.ts +++ b/backend/src/utils/userUtils.ts @@ -1,11 +1,10 @@ import { FastifyRequest } from 'fastify'; import * as _ from 'lodash'; +import { USER_ACCESS_TOKEN } from './constants'; import { KubeFastifyInstance } from '../types'; import { DEV_MODE } from './constants'; import { createCustomError } from './requestUtils'; -const USER_ACCESS_TOKEN = 'x-forwarded-access-token'; - export const usernameTranslate = (username: string): string => { const encodedUsername = encodeURIComponent(username); return encodedUsername diff --git a/docs/README.md b/docs/README.md index b37e932148..9615843b64 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,4 +6,5 @@ This project is divided into several sections, each one describing features of t * [Settings Panel](admin_dashboard.md) * [User Interaction](user_interaction.md) * [Bring Your Own Notebook](byon.md) -* [APIs](apis.md) +* [SDK](SDK.md) + * [Custom APIs](apis.md) -- Deprecated, moving to SDK diff --git a/docs/SDK.md b/docs/SDK.md new file mode 100644 index 0000000000..e324ef1a31 --- /dev/null +++ b/docs/SDK.md @@ -0,0 +1,63 @@ +# OpenShift Plugin SDK + +[@openshift/dynamic-plugin-sdk](https://www.npmjs.com/package/@openshift/dynamic-plugin-sdk) is an SDK package for making k8s related calls. + +It is technically split into three parts: + +- [@openshift/dynamic-plugin-sdk](https://www.npmjs.com/package/@openshift/dynamic-plugin-sdk) -- Core set of tools to build a plugin, we don't use this a lot today, but this is needed to bootstrap our frontend for later inclusion on other systems +- [@openshift/dynamic-plugin-sdk-utils](https://www.npmjs.com/package/@openshift/dynamic-plugin-sdk-utils) -- This will be where we will pull the most of our content from, it has all the k8s utilities we should need +- [@openshift/dynamic-plugin-sdk-webpack](https://www.npmjs.com/package/@openshift/dynamic-plugin-sdk-webpack) -- Simply just as it states, a webpack set of tools to help configure out webpack to package up to be an SDK + +As of today (2022-08-31), we are not looking to be a plugin. We just want to start moving that direction and making use of the utilities so we don't need custom backend to make API calls. + +## Making API Calls + +Instead of using our custom NodeJS backend, we'll want to migrate to using one of the following methods from the SDK. + +- k8sGetResource +- k8sCreateResource +- k8sUpdateResource +- k8sPatchResource +- k8sDeleteResource + +All these are heavily typed and are Generics`*`, so you should be able to infer from the types what is needed. But to help that along, here are a couple helpful notes: + +- `model` -- Models are simply just a collection of properties that describes a K8s Resource Type. K8s ones like `ConfigMap` & `Pod` to CRDs like `Notebook` and `OdhDashboardConfig` -- we will create our list of these under `frontend/src/models` -- check it out for examples. +- `queryOptions` -- These are just simply additional options to help target your call at something; typically you'll be setting `name` and `ns` (aka `namespace`) + +`*` A couple notes about the Generic nature of these functions + +1. You can type the response as well as your input -- aim to do this always for better typing, best have TS doing as much as possible +2. Our old types may not be 1:1 compatible with other resource types we have. Likely all you will need to do is convert over to the `K8sResourceCommon` type from the SDK instead of using ours + +### Pass Through API + +We have set up a pass through API that will effectively take the path built by the SDK's utilities during one of the k8s{CRUD}Resource calls noted above. This API will use the token of your user provided by our OAuth container and send your request off to a kube instance. We will give up on custom error handling and let the client deal with the error from k8s. + +See the [k8s pass through API](../backend/src/routes/api/k8s/pass-through.ts) here. + +## Patches + +Patches are based on [jsonpatch](https://jsonpatch.com/). For those who are unaware of the details let's do a quick breakdown on how they work. When making a `k8sPatchResource` call, it will ask for `Patches[]`. A `Patch` is just simply a straight forward operation on the existing resource. + +Say you wanted to update a `ConfigMap` to have a new property: + +```ts +import { k8sPatchResource } from '@openshift/dynamic-plugin-sdk-utils'; + +k8sPatchResource({ + model: ConfigMapModel, + queryOptions: { name: configMapName, ns: namespace }, + patches: [{ path: '/foo', op: 'add', value: 'bar' }] +}) +``` + +- `op` is what kind of operation to apply to this path + - 'add' -- adds a new item + - 'replace' -- updates an existing item + - 'remove' -- removes the item (you'd omit `value` naturally as there is no value for removing) + - There are other operations you can do as well ([see the docs](https://jsonpatch.com/#operations)) +- `path` is the path from the root of the k8s object using `/` as a deliminator, include the key you want to modify + - Unless it is a complex object you're adding, you'll likely specify `value` as a string/number + +Ideally you keep patches as small as needed to avoid any 409 Conflict errors. diff --git a/frontend/.eslintrc b/frontend/.eslintrc index a91130b93f..02670f8829 100755 --- a/frontend/.eslintrc +++ b/frontend/.eslintrc @@ -44,9 +44,10 @@ "@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/interface-name-prefix": "off", "@typescript-eslint/no-var-requires": "off", - "@typescript-eslint/no-empty-function": "warn", + "@typescript-eslint/no-empty-function": "error", "@typescript-eslint/no-inferrable-types": "error", - "react-hooks/exhaustive-deps": "warn", + "@typescript-eslint/no-unused-vars": "error", + "react-hooks/exhaustive-deps": "error", "react-hooks/rules-of-hooks": "error", "import/extensions": "off", "import/no-unresolved": "off", diff --git a/frontend/config/setupTests.js b/frontend/config/setupTests.js index 61ac1e8c14..a8133f6331 100644 --- a/frontend/config/setupTests.js +++ b/frontend/config/setupTests.js @@ -15,3 +15,5 @@ if (process.env.ODH_IS_PROJECT_ROOT_DIR === 'false') { configure({ testIdAttribute: 'data-id', }); + +jest.mock('@openshift/dynamic-plugin-sdk-utils', () => ({})); diff --git a/frontend/jest.config.js b/frontend/jest.config.js index 4222971c38..e200e7a0b7 100644 --- a/frontend/jest.config.js +++ b/frontend/jest.config.js @@ -16,8 +16,8 @@ module.exports = { branches: 0, functions: 0, lines: 0, - statements: 0 - } + statements: 0, + }, }, collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}'], @@ -30,7 +30,7 @@ module.exports = { '\\.(css|less|sass|scss)$': '/config/transform.style.js', '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '/config/transform.file.js', - '@app/(.*)': '/src/app/$1' + '@app/(.*)': '/src/app/$1', }, // A preset that is used as a base for Jest's configuration @@ -42,6 +42,10 @@ module.exports = { // The test environment that will be used for testing. testEnvironment: 'jsdom', + transform: { + 'node_modules/.+\\.(j|t)sx?$': 'ts-jest', + }, + // A list of paths to snapshot serializer modules Jest should use for snapshot testing - snapshotSerializers: [] + snapshotSerializers: [], }; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 93d3ffd54b..de3990afca 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1081,12 +1081,24 @@ "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } } }, "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", + "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", "dev": true }, "@jridgewell/set-array": { @@ -1103,24 +1115,26 @@ "requires": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } } }, "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", + "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", "dev": true }, - "@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1167,6 +1181,34 @@ "rimraf": "^3.0.2" } }, + "@openshift/dynamic-plugin-sdk": { + "version": "1.0.0-alpha12", + "resolved": "https://registry.npmjs.org/@openshift/dynamic-plugin-sdk/-/dynamic-plugin-sdk-1.0.0-alpha12.tgz", + "integrity": "sha512-DFhc5y2kgUhYhMPR1zYge/PLvchFHZ6VA1UMA9tbQZNYQLydgD2CyIzOw/W1qsTN6u9FoFkHANplxuN1p87p9w==", + "requires": { + "lodash-es": "^4.17.21", + "yup": "^0.32.11" + } + }, + "@openshift/dynamic-plugin-sdk-utils": { + "version": "1.0.0-alpha17", + "resolved": "https://registry.npmjs.org/@openshift/dynamic-plugin-sdk-utils/-/dynamic-plugin-sdk-utils-1.0.0-alpha17.tgz", + "integrity": "sha512-IravFesEE+BNBQgSDq6kAkAPh1U/HbFqefuyE+85gANygcPzzY5AXVOIZC3LoysKMjPOtwYidwpc3nENUZKWGg==", + "requires": { + "immutable": "^3.8.2", + "lodash-es": "^4.17.21", + "pluralize": "^8.0.0", + "typesafe-actions": "^4.4.2", + "uuid": "^8.3.2" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } + } + }, "@patternfly/patternfly": { "version": "4.215.1", "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.215.1.tgz", @@ -1217,6 +1259,45 @@ "@patternfly/patternfly": "4.215.1", "@patternfly/react-core": "^4.239.0", "@patternfly/react-styles": "^4.89.0" + }, + "dependencies": { + "@patternfly/patternfly": { + "version": "4.215.1", + "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.215.1.tgz", + "integrity": "sha512-coOipHiQs92OYYO+pWfukEKOkY+VUL6ptusTxh98DvIu/tQYzJDJxEmzYXmwqxORM19oLxAJEGktPoLNKElj6A==" + }, + "@patternfly/react-core": { + "version": "4.239.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.239.0.tgz", + "integrity": "sha512-6CmYABCJLUXTlzCk6C3WouMNZpS0BCT+aHU8CvYpFQ/NrpYp3MJaDsYbqgCRWV42rmIO5iXun/4WhXBJzJEoQg==", + "requires": { + "@patternfly/react-icons": "^4.90.0", + "@patternfly/react-styles": "^4.89.0", + "@patternfly/react-tokens": "^4.91.0", + "focus-trap": "6.9.2", + "react-dropzone": "9.0.0", + "tippy.js": "5.1.2", + "tslib": "^2.0.0" + } + }, + "@patternfly/react-icons": { + "version": "4.90.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.90.0.tgz", + "integrity": "sha512-qEnQKbxbUgyiosiKSkeKEBwmhgJwWEqniIAFyoxj+kpzAdeu7ueWe5iBbqo06mvDOedecFiM5mIE1N0MXwk8Yw==" + }, + "@patternfly/react-styles": { + "version": "4.89.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.89.0.tgz", + "integrity": "sha512-SkT+qx3Xqu70T5s+i/AUT2hI2sKAPDX4ffeiJIUDu/oyWiFdk+/9DEivnLSyJMruroXXN33zKibvzb5rH7DKTQ==" + }, + "focus-trap": { + "version": "6.9.2", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.9.2.tgz", + "integrity": "sha512-gBEuXOPNOKPrLdZpMFUSTyIo1eT2NSZRrwZ9r/0Jqw5tmT3Yvxfmu8KBHw8xW2XQkw6E/JoG+OlEq7UDtSUNgw==", + "requires": { + "tabbable": "^5.3.2" + } + } } }, "@patternfly/react-core": { @@ -1261,11 +1342,62 @@ "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.91.0.tgz", "integrity": "sha512-QeQCy8o8E/16fAr8mxqXIYRmpTsjCHJXi5p5jmgEDFmYMesN6Pqfv6N5D0FHb+CIaNOZWRps7GkWvlIMIE81sw==" }, - "@polka/url": { - "version": "1.0.0-next.21", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", - "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", - "dev": true + "@patternfly/react-virtualized-extension": { + "version": "4.71.1", + "resolved": "https://registry.npmjs.org/@patternfly/react-virtualized-extension/-/react-virtualized-extension-4.71.1.tgz", + "integrity": "sha512-hlMuFx8jtnj9CeYVYqVJmb9QXUP3BVwTjqIAugTwrVpS3NcRRC5Acxof4GEqUUrx+oYb/SxR96+EAc8VusuZFw==", + "requires": { + "@patternfly/react-core": "^4.224.1", + "@patternfly/react-icons": "^4.75.1", + "@patternfly/react-styles": "^4.74.1", + "linear-layout-vector": "0.0.1", + "react-virtualized": "^9.21.1", + "tslib": "^2.0.0" + }, + "dependencies": { + "@patternfly/react-core": { + "version": "4.224.1", + "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.224.1.tgz", + "integrity": "sha512-v8wGGNoMGndAScAoE5jeOA5jVgymlLSwttPjQk/Idr0k7roSpOrsM39oXUR5DEgkZee45DW00WKTgmg50PP3FQ==", + "requires": { + "@patternfly/react-icons": "^4.75.1", + "@patternfly/react-styles": "^4.74.1", + "@patternfly/react-tokens": "^4.76.1", + "focus-trap": "6.9.2", + "react-dropzone": "9.0.0", + "tippy.js": "5.1.2", + "tslib": "^2.0.0" + } + }, + "@patternfly/react-icons": { + "version": "4.75.1", + "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.75.1.tgz", + "integrity": "sha512-1ly8SVi/kcc0zkiViOjUd8D5BEr7GeqWGmDPuDSBtD60l1dYf3hZc44IWFVkRM/oHZML/musdrJkLfh4MDqX9w==" + }, + "@patternfly/react-styles": { + "version": "4.74.1", + "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.74.1.tgz", + "integrity": "sha512-9eWvKrjtrJ3qhJkhY2GQKyYA13u/J0mU1befH49SYbvxZtkbuHdpKmXBAeQoHmcx1hcOKtiYXeKb+dVoRRNx0A==" + }, + "@patternfly/react-tokens": { + "version": "4.76.1", + "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.76.1.tgz", + "integrity": "sha512-gLEezRSzQeflaPu3SCgYmWtuiqDIRtxNNFP1+ES7P2o56YHXJ5o1Pki7LpNCPk/VOzHy2+vRFE/7l+hBEweugw==" + }, + "focus-trap": { + "version": "6.9.2", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.9.2.tgz", + "integrity": "sha512-gBEuXOPNOKPrLdZpMFUSTyIo1eT2NSZRrwZ9r/0Jqw5tmT3Yvxfmu8KBHw8xW2XQkw6E/JoG+OlEq7UDtSUNgw==", + "requires": { + "tabbable": "^5.3.2" + } + }, + "tabbable": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", + "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==" + } + } }, "@remix-run/router": { "version": "1.0.1", @@ -1413,6 +1545,32 @@ "classnames": "*" } }, + "@types/eslint": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz", + "integrity": "sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, "@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -1448,9 +1606,9 @@ } }, "@types/html-minifier-terser": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz", - "integrity": "sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", "dev": true }, "@types/istanbul-lib-coverage": { @@ -1559,6 +1717,11 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "@types/lodash": { + "version": "4.14.182", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", + "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==" + }, "@types/minimatch": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", @@ -1656,24 +1819,12 @@ "integrity": "sha512-50ehC3IAijfkvoNqmQ+VL73S7orOxmAK8ljQAFBv8o7G66lAZyxQj1L3BAv2dD86myLXI+sgKP1kcxAaxW356w==", "dev": true }, - "@types/source-list-map": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", - "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", - "dev": true - }, "@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, - "@types/tapable": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.8.tgz", - "integrity": "sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ==", - "dev": true - }, "@types/testing-library__jest-dom": { "version": "5.14.3", "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.3.tgz", @@ -1683,48 +1834,6 @@ "@types/jest": "*" } }, - "@types/uglify-js": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.1.tgz", - "integrity": "sha512-O3MmRAk6ZuAKa9CHgg0Pr0+lUOqoMLpc9AS4R8ano2auvsg7IE8syF3Xh/NPr26TWklxYcqoEEFdzLLs1fV9PQ==", - "dev": true, - "requires": { - "source-map": "^0.6.1" - } - }, - "@types/webpack": { - "version": "4.41.32", - "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.32.tgz", - "integrity": "sha512-cb+0ioil/7oz5//7tZUSwbrSAN/NWHrQylz5cW8G0dWTcF/g+/dSdMlKVZspBYuMAN1+WnwHrkxiRrLcwd0Heg==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/tapable": "^1", - "@types/uglify-js": "*", - "@types/webpack-sources": "*", - "anymatch": "^3.0.0", - "source-map": "^0.6.0" - } - }, - "@types/webpack-sources": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-3.2.0.tgz", - "integrity": "sha512-Ft7YH3lEVRQ6ls8k4Ff1oB4jN6oy/XmU6tQISKdhfh+1mR+viZFphS6WL0IrtDOzvefmJg5a0s7ZQoRXwqTEFg==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/source-list-map": "*", - "source-map": "^0.7.3" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } - } - }, "@types/yargs": { "version": "15.0.14", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", @@ -1824,177 +1933,148 @@ } }, "@webassemblyjs/ast": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", - "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", "dev": true, "requires": { - "@webassemblyjs/helper-module-context": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/wast-parser": "1.9.0" + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" } }, "@webassemblyjs/floating-point-hex-parser": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", - "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", "dev": true }, "@webassemblyjs/helper-api-error": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", - "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", "dev": true }, "@webassemblyjs/helper-buffer": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", - "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==", - "dev": true - }, - "@webassemblyjs/helper-code-frame": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", - "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", - "dev": true, - "requires": { - "@webassemblyjs/wast-printer": "1.9.0" - } - }, - "@webassemblyjs/helper-fsm": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", - "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", "dev": true }, - "@webassemblyjs/helper-module-context": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", - "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.9.0" + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" } }, "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", - "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", "dev": true }, "@webassemblyjs/helper-wasm-section": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", - "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0" + "@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": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", - "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", "dev": true, "requires": { "@xtuc/ieee754": "^1.2.0" } }, "@webassemblyjs/leb128": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", - "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", "dev": true, "requires": { "@xtuc/long": "4.2.2" } }, "@webassemblyjs/utf8": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", - "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", "dev": true }, "@webassemblyjs/wasm-edit": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", - "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/helper-wasm-section": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0", - "@webassemblyjs/wasm-opt": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0", - "@webassemblyjs/wast-printer": "1.9.0" + "@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": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", - "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/ieee754": "1.9.0", - "@webassemblyjs/leb128": "1.9.0", - "@webassemblyjs/utf8": "1.9.0" + "@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": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", - "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0" + "@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": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", - "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-api-error": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/ieee754": "1.9.0", - "@webassemblyjs/leb128": "1.9.0", - "@webassemblyjs/utf8": "1.9.0" - } - }, - "@webassemblyjs/wast-parser": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", - "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/floating-point-hex-parser": "1.9.0", - "@webassemblyjs/helper-api-error": "1.9.0", - "@webassemblyjs/helper-code-frame": "1.9.0", - "@webassemblyjs/helper-fsm": "1.9.0", - "@xtuc/long": "4.2.2" + "@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": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", - "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/wast-parser": "1.9.0", + "@webassemblyjs/ast": "1.11.1", "@xtuc/long": "4.2.2" } }, @@ -2146,6 +2226,12 @@ "acorn-walk": "^7.1.1" } }, + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true + }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -2372,53 +2458,6 @@ "safer-buffer": "~2.1.0" } }, - "asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, - "assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", - "dev": true, - "requires": { - "object-assign": "^4.1.1", - "util": "0.10.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==", - "dev": true - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ==", - "dev": true, - "requires": { - "inherits": "2.0.1" - } - } - } - }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -2642,12 +2681,6 @@ } } }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, "batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -2668,13 +2701,6 @@ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "optional": true - }, "bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", @@ -2699,12 +2725,6 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, - "bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==", - "dev": true - }, "body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", @@ -2790,110 +2810,12 @@ "fill-range": "^7.0.1" } }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true - }, "browser-process-hrtime": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", "dev": true }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dev": true, - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "browserify-rsa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", - "dev": true, - "requires": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", - "dev": true, - "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - } - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "dev": true, - "requires": { - "pako": "~1.0.5" - } - }, "browserslist": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.0.tgz", @@ -2925,17 +2847,6 @@ "node-int64": "^0.4.0" } }, - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "dev": true, - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -2948,18 +2859,6 @@ "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", "dev": true }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "dev": true - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", - "dev": true - }, "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", @@ -3147,23 +3046,6 @@ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "optional": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, "chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -3181,16 +3063,6 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, "cjs-module-lexer": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", @@ -3226,9 +3098,9 @@ "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" }, "clean-css": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", - "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.1.tgz", + "integrity": "sha512-lCr8OHhiWCTw4v8POJovCoh4T7I9U11yVsPjMWWnnMmp9ZowCxyad1Pathle/9HjaDp+fdQKjO9fQydE6RHTZg==", "dev": true, "requires": { "source-map": "~0.6.0" @@ -3248,17 +3120,6 @@ "string-width": "^2.1.1", "strip-ansi": "^4.0.0", "wrap-ansi": "^2.0.0" - }, - "dependencies": { - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - } } }, "clone-deep": { @@ -3272,6 +3133,11 @@ "shallow-clone": "^3.0.0" } }, + "clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -3429,9 +3295,9 @@ } }, "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "dev": true }, "commondir": { @@ -3497,41 +3363,17 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, "connect-history-api-fallback": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", "dev": true }, - "console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", - "dev": true - }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", - "dev": true - }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -3576,40 +3418,6 @@ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", "dev": true }, - "copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", @@ -3753,51 +3561,6 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, - "create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", @@ -3808,25 +3571,6 @@ "which": "^1.2.9" } }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dev": true, - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, "css": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", @@ -4163,12 +3907,6 @@ "array-find-index": "^1.0.1" } }, - "cyclist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", - "integrity": "sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A==", - "dev": true - }, "d": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", @@ -4439,16 +4177,6 @@ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", "dev": true }, - "des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, "destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", @@ -4467,25 +4195,6 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -4552,6 +4261,15 @@ "utila": "~0.4" } }, + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "dom-serializer": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", @@ -4570,12 +4288,6 @@ } } }, - "domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", - "dev": true - }, "domelementtype": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", @@ -4600,18 +4312,18 @@ } }, "domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, "requires": { "domelementtype": "^2.2.0" }, "dependencies": { "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true } } @@ -4686,18 +4398,6 @@ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "dev": true }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "dev": true, - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -4713,35 +4413,18 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", "dev": true }, + "ejs": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", + "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", + "dev": true + }, "electron-to-chromium": { "version": "1.4.78", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.78.tgz", "integrity": "sha512-o61+D/Lx7j/E0LIin/efOqeHpXhwi1TaQco9vUcRmr91m25SfZY6L5hWJDv/r+6kNjboFKgBw1LbfM0lbhuK6Q==", "dev": true }, - "elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dev": true, - "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, "emittery": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", @@ -4868,6 +4551,12 @@ "unbox-primitive": "^1.0.1" } }, + "es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, "es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -5341,14 +5030,13 @@ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "eventsource": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", + "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", "dev": true, "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" + "original": "^1.0.0" } }, "exec-sh": { @@ -5764,12 +5452,6 @@ "bser": "2.1.1" } }, - "figgy-pudding": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", - "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", - "dev": true - }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -5864,17 +5546,6 @@ } } }, - "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - } - }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -5899,16 +5570,6 @@ "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, - "flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, "focus-trap": { "version": "6.9.2", "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.9.2.tgz", @@ -5964,16 +5625,6 @@ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", "dev": true }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, "fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -5982,18 +5633,6 @@ "minipass": "^3.0.0" } }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -6186,6 +5825,12 @@ "is-glob": "^4.0.1" } }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -6252,12 +5897,21 @@ "optional": true }, "gzip-size": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", - "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", + "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", "dev": true, "requires": { - "duplexer": "^0.1.2" + "duplexer": "^0.1.1", + "pify": "^4.0.1" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } } }, "handle-thing": { @@ -6387,46 +6041,6 @@ } } }, - "hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "dev": true, - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - } - } - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -6447,17 +6061,6 @@ "@babel/runtime": "^7.7.6" } }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dev": true, - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, "hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -6466,6 +6069,12 @@ "react-is": "^16.7.0" } }, + "hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", + "dev": true + }, "hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -6517,66 +6126,66 @@ "dev": true }, "html-minifier-terser": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", - "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", "dev": true, "requires": { - "camel-case": "^4.1.1", - "clean-css": "^4.2.3", - "commander": "^4.1.1", + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", "he": "^1.2.0", - "param-case": "^3.0.3", + "param-case": "^3.0.4", "relateurl": "^0.2.7", - "terser": "^4.6.3" + "terser": "^5.10.0" + }, + "dependencies": { + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true + }, + "terser": { + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + } } }, "html-webpack-plugin": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.0.tgz", - "integrity": "sha512-MouoXEYSjTzCrjIxWwg8gxL5fE2X2WZJLmBYXlaJhQUH5K/b5OrqmV7T4dB7iu0xkmJ6JlUuV6fFVtnqbPopZw==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", + "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", "dev": true, "requires": { - "@types/html-minifier-terser": "^5.0.0", - "@types/tapable": "^1.0.5", - "@types/webpack": "^4.41.8", - "html-minifier-terser": "^5.0.1", - "loader-utils": "^1.2.3", - "lodash": "^4.17.15", - "pretty-error": "^2.1.1", - "tapable": "^1.1.3", - "util.promisify": "1.0.0" + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" }, "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - } - }, - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true } } }, @@ -6593,9 +6202,9 @@ }, "dependencies": { "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, "requires": { "domelementtype": "^2.0.1", @@ -6604,9 +6213,9 @@ } }, "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true }, "domutils": { @@ -6790,12 +6399,6 @@ "sshpk": "^1.7.0" } }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", - "dev": true - }, "https-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", @@ -6821,18 +6424,6 @@ "safer-buffer": ">= 2.1.2 < 3" } }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==", - "dev": true - }, "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -6887,6 +6478,11 @@ } } }, + "immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==" + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -7110,16 +6706,6 @@ "has-bigints": "^1.0.1" } }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "optional": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, "is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -9380,6 +8966,11 @@ "type-check": "~0.4.0" } }, + "linear-layout-vector": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/linear-layout-vector/-/linear-layout-vector-0.0.1.tgz", + "integrity": "sha512-w+nr1ZOVFGyMhwr8JKo0YzqDc8C2Z7pc9UbTuJA4VG/ezlSFEx+7kNrfCYvq7JQ/jHKR+FWy6reNrkVVzm0hSA==" + }, "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -9399,9 +8990,9 @@ } }, "loader-runner": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "dev": true }, "loader-utils": { @@ -9582,30 +9173,6 @@ "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==", "dev": true }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, "make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -9641,17 +9208,6 @@ "object-visit": "^1.0.0" } }, - "md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, "mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", @@ -9766,24 +9322,6 @@ "picomatch": "^2.2.3" } }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -9844,12 +9382,6 @@ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "dev": true }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "dev": true - }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -9921,24 +9453,6 @@ } } }, - "mississippi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", - "dev": true, - "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - } - }, "mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -9965,46 +9479,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ==", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "mrmime": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", - "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -10032,6 +9506,11 @@ "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==" }, + "nanoclone": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz", + "integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==" + }, "nanoid": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", @@ -10136,45 +9615,6 @@ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", "dev": true }, - "node-libs-browser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", - "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", - "dev": true, - "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", - "dev": true - } - } - }, "node-notifier": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", @@ -10819,11 +10259,14 @@ "word-wrap": "^1.2.3" } }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", - "dev": true + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dev": true, + "requires": { + "url-parse": "^1.4.3" + } }, "os-homedir": { "version": "1.0.2", @@ -10910,23 +10353,6 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" }, - "pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true - }, - "parallel-transform": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", - "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", - "dev": true, - "requires": { - "cyclist": "^1.0.1", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - } - }, "param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -10946,19 +10372,6 @@ "callsites": "^3.0.0" } }, - "parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "dev": true, - "requires": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", @@ -10995,12 +10408,6 @@ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", "dev": true }, - "path-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", - "dev": true - }, "path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", @@ -11043,19 +10450,6 @@ "pinkie-promise": "^2.0.0" } }, - "pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "dev": true, - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -11157,6 +10551,11 @@ } } }, + "pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==" + }, "popper.js": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", @@ -11723,13 +11122,13 @@ } }, "pretty-error": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", - "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", "dev": true, "requires": { "lodash": "^4.17.20", - "renderkid": "^2.0.4" + "renderkid": "^3.0.0" } }, "pretty-format": { @@ -11763,12 +11162,6 @@ } } }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true - }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -11815,6 +11208,11 @@ "warning": "^4.0.0" } }, + "property-expr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz", + "integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA==" + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -11841,28 +11239,6 @@ "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -11873,29 +11249,6 @@ "once": "^1.3.1" } }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "dev": true, - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -11912,12 +11265,6 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", - "dev": true - }, "querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -11939,16 +11286,6 @@ "safe-buffer": "^5.1.0" } }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -12077,6 +11414,11 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, "react-redux": { "version": "7.2.6", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz", @@ -12114,6 +11456,19 @@ "react-router": "6.4.1" } }, + "react-virtualized": { + "version": "9.22.3", + "resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.3.tgz", + "integrity": "sha512-MKovKMxWTcwPSxE1kK1HcheQTWfuCxAuBoSTf2gwyMM21NdX/PXUhnoP8Uc5dRKd+nKm8v41R36OellhdCpkrw==", + "requires": { + "@babel/runtime": "^7.7.2", + "clsx": "^1.0.4", + "dom-helpers": "^5.1.3", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-lifecycles-compat": "^3.0.4" + } + }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", @@ -12166,16 +11521,6 @@ "util-deprecate": "~1.0.1" } }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "optional": true, - "requires": { - "picomatch": "^2.2.1" - } - }, "rechoir": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", @@ -12261,47 +11606,47 @@ "dev": true }, "renderkid": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", - "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", "dev": true, "requires": { "css-select": "^4.1.3", "dom-converter": "^0.2.0", "htmlparser2": "^6.1.0", "lodash": "^4.17.21", - "strip-ansi": "^3.0.1" + "strip-ansi": "^6.0.1" }, "dependencies": { "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dev": true, "requires": { "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", "domutils": "^2.8.0", "nth-check": "^2.0.1" } }, "css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true }, "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, "requires": { "domelementtype": "^2.0.1", @@ -12310,9 +11655,9 @@ } }, "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true }, "domutils": { @@ -12327,21 +11672,21 @@ } }, "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, "requires": { "boolbase": "^1.0.0" } }, "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^5.0.1" } } } @@ -12498,16 +11843,6 @@ "glob": "^7.1.3" } }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, "rsvp": { "version": "4.8.5", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", @@ -12523,15 +11858,6 @@ "queue-microtask": "^1.2.2" } }, - "run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==", - "dev": true, - "requires": { - "aproba": "^1.1.1" - } - }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -13186,28 +12512,12 @@ } } }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true - }, "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, "shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -13231,9 +12541,9 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, "shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", "dev": true }, "shellwords": { @@ -13435,17 +12745,6 @@ } } }, - "sirv": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", - "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", - "dev": true, - "requires": { - "@polka/url": "^1.0.0-next.20", - "mrmime": "^1.0.0", - "totalist": "^1.0.0" - } - }, "sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -13828,45 +13127,6 @@ "readable-stream": "^2.0.1" } }, - "stream-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", - "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "stream-each": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", - "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "stream-http": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", - "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", - "dev": true, - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - } - }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", - "dev": true - }, "string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -13895,38 +13155,12 @@ } }, "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - } + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "string.prototype.matchall": { @@ -14319,25 +13553,6 @@ "supports-hyperlinks": "^2.0.0" } }, - "terser": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", - "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", - "dev": true, - "requires": { - "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - } - } - }, "terser-webpack-plugin": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz", @@ -14356,9 +13571,9 @@ }, "dependencies": { "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "dev": true }, "commander": { @@ -14474,15 +13689,23 @@ "dev": true }, "terser": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz", - "integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==", + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.12.0.tgz", + "integrity": "sha512-R3AUhNBGWiFc77HXag+1fXpAxTAFRQTJemlJKjAgD9r8xXTpjNKqIXwHM/o7Rh+O0kUJtS3WQVdBeMKFk5sw9A==", "dev": true, "requires": { - "@jridgewell/source-map": "^0.3.2", "acorn": "^8.5.0", "commander": "^2.20.0", + "source-map": "~0.7.2", "source-map-support": "~0.5.20" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } } } } @@ -14510,31 +13733,12 @@ "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", "dev": true }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, - "timers-browserify": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", - "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", - "dev": true, - "requires": { - "setimmediate": "^1.0.4" - } - }, "timsort": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", @@ -14555,12 +13759,6 @@ "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==", - "dev": true - }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -14614,11 +13812,10 @@ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true }, - "totalist": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", - "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", - "dev": true + "toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" }, "tough-cookie": { "version": "2.5.0", @@ -14651,6 +13848,12 @@ "glob": "^7.1.2" } }, + "tryer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", + "dev": true + }, "ts-jest": { "version": "26.5.6", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz", @@ -14792,12 +13995,6 @@ } } }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==", - "dev": true - }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -14848,12 +14045,6 @@ "mime-types": "~2.1.24" } }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true - }, "typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -14863,6 +14054,11 @@ "is-typedarray": "^1.0.0" } }, + "typesafe-actions": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/typesafe-actions/-/typesafe-actions-4.4.2.tgz", + "integrity": "sha512-QW61P4cOX8dCNmrfpcUMjvU/MF/sFTC8/PlG9215W1gKDzZUBjRGdyYSO6ZcEUNsn491S2VpryJOHSIVSDqJrg==" + }, "typescript": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", @@ -15065,23 +14261,6 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, - "util": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", - "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", - "dev": true, - "requires": { - "inherits": "2.0.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true - } - } - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -15179,12 +14358,6 @@ } } }, - "vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", - "dev": true - }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -15221,465 +14394,264 @@ } }, "watchpack": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", - "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dev": true, "requires": { - "chokidar": "^3.4.1", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0", - "watchpack-chokidar2": "^2.0.1" + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" } }, - "watchpack-chokidar2": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", - "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, - "optional": true, "requires": { - "chokidar": "^2.1.8" + "minimalistic-assert": "^1.0.0" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true + }, + "webpack": { + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "dev": true, + "requires": { + "@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" }, "dependencies": { - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", "dev": true, - "optional": true, "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "optional": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true, - "optional": true + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "enhanced-resolve": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", "dev": true, - "optional": true, "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" } }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, - "optional": true, "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" } }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", "dev": true, - "optional": true, "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" } }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", "dev": true, - "optional": true, "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" + "randombytes": "^2.1.0" } }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, - "optional": true, "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "optional": true, - "requires": { - "is-extglob": "^2.1.0" - } - } + "has-flag": "^4.0.0" } }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, + "terser": { + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "dev": true, - "optional": true, "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "optional": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" } }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "terser-webpack-plugin": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz", + "integrity": "sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ==", "dev": true, - "optional": true, "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "@jridgewell/trace-mapping": "^0.3.7", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.7.2" } }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "optional": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true } } }, - "wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "webpack-bundle-analyzer": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.9.0.tgz", + "integrity": "sha512-Ob8amZfCm3rMB1ScjQVlbYYUEJyEjdEtQ92jqiFUYt5VkEeO2v5UMbv49P/gnmCZm3A6yaFQzCBvpZqN4MUsdA==", "dev": true, "requires": { - "minimalistic-assert": "^1.0.0" - } - }, - "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true - }, - "webpack": { - "version": "4.44.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.2.tgz", - "integrity": "sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-module-context": "1.9.0", - "@webassemblyjs/wasm-edit": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0", - "acorn": "^6.4.1", - "ajv": "^6.10.2", - "ajv-keywords": "^3.4.1", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^4.3.0", - "eslint-scope": "^4.0.3", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.4.0", - "loader-utils": "^1.2.3", - "memory-fs": "^0.4.1", - "micromatch": "^3.1.10", - "mkdirp": "^0.5.3", - "neo-async": "^2.6.1", - "node-libs-browser": "^2.2.1", - "schema-utils": "^1.0.0", - "tapable": "^1.1.3", - "terser-webpack-plugin": "^1.4.3", - "watchpack": "^1.7.4", - "webpack-sources": "^1.4.1" + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1", + "bfj": "^6.1.1", + "chalk": "^2.4.1", + "commander": "^2.18.0", + "ejs": "^2.6.1", + "express": "^4.16.3", + "filesize": "^3.6.1", + "gzip-size": "^5.0.0", + "lodash": "^4.17.19", + "mkdirp": "^0.5.1", + "opener": "^1.5.1", + "ws": "^6.0.0" }, "dependencies": { - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "color-convert": "^1.9.0" } }, - "cacache": { - "version": "12.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", - "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "bfj": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.2.tgz", + "integrity": "sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw==", "dev": true, "requires": { "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "check-types": "^8.0.3", + "hoopy": "^0.1.4", + "tryer": "^1.0.1" } }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "check-types": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-8.0.3.tgz", + "integrity": "sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ==", "dev": true }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { - "minimist": "^1.2.0" + "color-name": "1.1.3" } }, - "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - } + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } + "filesize": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", + "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true }, "mkdirp": { "version": "0.5.5", @@ -15690,129 +14662,23 @@ "minimist": "^1.2.5" } }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "ssri": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", - "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", - "dev": true, - "requires": { - "figgy-pudding": "^3.5.1" - } - }, - "terser-webpack-plugin": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", - "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", - "dev": true, - "requires": { - "cacache": "^12.0.2", - "find-cache-dir": "^2.1.0", - "is-wsl": "^1.1.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^4.0.0", - "source-map": "^0.6.1", - "terser": "^4.1.2", - "webpack-sources": "^1.4.0", - "worker-farm": "^1.7.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "has-flag": "^3.0.0" } }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - } - } - }, - "webpack-bundle-analyzer": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.6.1.tgz", - "integrity": "sha512-oKz9Oz9j3rUciLNfpGFjOb49/jEpXNmWdVH8Ls//zNcnLlQdTGXQQMsBbb/gR7Zl8WNLxVCq+0Hqbx3zv6twBw==", - "dev": true, - "requires": { - "acorn": "^8.0.4", - "acorn-walk": "^8.0.0", - "chalk": "^4.1.0", - "commander": "^7.2.0", - "gzip-size": "^6.0.0", - "lodash": "^4.17.20", - "opener": "^1.5.2", - "sirv": "^1.0.7", - "ws": "^7.3.1" - }, - "dependencies": { - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "ws": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", + "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "async-limiter": "~1.0.0" } - }, - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true } } }, @@ -16408,12 +15274,6 @@ "ms": "^2.1.1" } }, - "eventsource": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.2.tgz", - "integrity": "sha512-xAH3zWhgO2/3KIniEKYPr8plNSzlGINOUqYj0m0u7AB81iRw8b/3E73W6AuU+6klLbaSFmZnaETQ2lXPfAydrA==", - "dev": true - }, "faye-websocket": { "version": "0.11.4", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", @@ -16679,15 +15539,6 @@ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, - "worker-farm": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", - "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", - "dev": true, - "requires": { - "errno": "~0.1.7" - } - }, "wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", @@ -16765,12 +15616,6 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true - }, "y18n": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", @@ -16781,6 +15626,11 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" }, + "yaml": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.3.tgz", + "integrity": "sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==" + }, "yargs": { "version": "10.1.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.1.2.tgz", @@ -16798,17 +15648,6 @@ "which-module": "^2.0.0", "y18n": "^3.2.1", "yargs-parser": "^8.1.0" - }, - "dependencies": { - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - } } }, "yargs-parser": { @@ -16824,6 +15663,20 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true + }, + "yup": { + "version": "0.32.11", + "resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz", + "integrity": "sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==", + "requires": { + "@babel/runtime": "^7.15.4", + "@types/lodash": "^4.14.175", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "nanoclone": "^0.2.1", + "property-expr": "^2.0.4", + "toposort": "^2.0.2" + } } } } diff --git a/frontend/package.json b/frontend/package.json index a73cc24335..7b330ada80 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -36,6 +36,8 @@ "test:type-check": "tsc --noEmit" }, "dependencies": { + "@openshift/dynamic-plugin-sdk": "^1.0.0-alpha12", + "@openshift/dynamic-plugin-sdk-utils": "^1.0.0-alpha17", "@patternfly/patternfly": "4.215.1", "@patternfly/quickstarts": "^2.3.1", "@patternfly/react-catalog-view-extension": "4.90.0", @@ -43,6 +45,7 @@ "@patternfly/react-icons": "4.90.0", "@patternfly/react-styles": "4.89.0", "@patternfly/react-table": "4.108.0", + "@patternfly/react-virtualized-extension": "^4.71.1", "@types/classnames": "^2.3.1", "axios": "^0.21.1", "classnames": "^2.2.6", @@ -59,7 +62,8 @@ "react-router-dom": "^6.4.1", "redux": "^4.0.5", "redux-thunk": "^2.3.0", - "showdown": "^1.9.1" + "showdown": "^1.9.1", + "yaml": "^2.1.3" }, "devDependencies": { "@testing-library/dom": "^8.13.0", @@ -83,7 +87,7 @@ "eslint-plugin-react": "^7.21.4", "eslint-plugin-react-hooks": "^4.1.2", "file-loader": "^6.1.1", - "html-webpack-plugin": "^4.5.0", + "html-webpack-plugin": "^5.5.0", "imagemin": "^7.0.0", "jest": "^26.6.0", "js-yaml-loader": "^1.2.2", @@ -107,8 +111,8 @@ "tslib": "^2.0.3", "typescript": "^4.0.3", "url-loader": "^4.1.1", - "webpack": "4.44.2", - "webpack-bundle-analyzer": "^4.6.1", + "webpack": "^5.74.0", + "webpack-bundle-analyzer": "^3.9.0", "webpack-cli": "^4.2.0", "webpack-dev-server": "3.11.0", "webpack-merge": "^5.2.0" diff --git a/frontend/src/SDKInitialize.tsx b/frontend/src/SDKInitialize.tsx new file mode 100644 index 0000000000..b92819355e --- /dev/null +++ b/frontend/src/SDKInitialize.tsx @@ -0,0 +1,53 @@ +import * as React from 'react'; +import { AppInitSDK, isUtilsConfigSet } from '@openshift/dynamic-plugin-sdk-utils'; +import { PluginLoader, PluginStore } from '@openshift/dynamic-plugin-sdk'; +import { Bullseye, Spinner } from '@patternfly/react-core'; + +const config: React.ComponentProps['configurations'] = { + appFetch: (url, options) => { + // Using fetch instead of axios because of internal SDK structures that needs to use `response.text` + return fetch(`/api/k8s${url}`, options); + }, + + /** Disable api discovery -- until we need to use the k8s watch hooks, we don't need to use api discovery */ + apiDiscovery: () => null, + /** We don't need a plugin store yet -- we just want the SDK setup for utilities right now */ + pluginStore: (() => { + const pluginStore = new PluginStore(); + pluginStore.setLoader(new PluginLoader()); + return pluginStore; + })(), + /** + * No need for web sockets at this point -- we'll need to support this if we want to use the + * websocket utilities or the k8s watch hooks. + */ + wsAppSettings: () => Promise.resolve({ host: '', subProtocols: [] }), +}; + +const SDKInitialize: React.FC = ({ children }) => { + // hack to make sure the SDK has fully loaded before we try to render the app + // TODO: Figure out what's going on in the SDK + const [ready, setReady] = React.useState(false); + React.useEffect(() => { + const intervalId = setInterval(() => { + if (isUtilsConfigSet()) { + setReady(true); + clearInterval(intervalId); + } + }, 1000); + }, []); + + return ( + + {ready ? ( + children + ) : ( + + + + )} + + ); +}; + +export default SDKInitialize; diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts new file mode 100644 index 0000000000..c937fc4541 --- /dev/null +++ b/frontend/src/api/index.ts @@ -0,0 +1,15 @@ +// Normal SDK/pass-through network API calls +export * from './network/builds'; +export * from './network/configMaps'; +export * from './network/events'; +export * from './network/imageStreams'; +export * from './network/notebooks'; +export * from './network/pods'; +export * from './network/projects'; +export * from './network/pvcs'; +export * from './network/roleBindings'; +export * from './network/routes'; +export * from './network/secrets'; + +// Prometheus queries +export * from './prometheus/pvcs'; diff --git a/frontend/src/api/models/index.ts b/frontend/src/api/models/index.ts new file mode 100644 index 0000000000..452ca48278 --- /dev/null +++ b/frontend/src/api/models/index.ts @@ -0,0 +1,3 @@ +export * from './k8s'; +export * from './odh'; +export * from './openShift'; diff --git a/frontend/src/api/models/k8s.ts b/frontend/src/api/models/k8s.ts new file mode 100644 index 0000000000..99572b9595 --- /dev/null +++ b/frontend/src/api/models/k8s.ts @@ -0,0 +1,38 @@ +import { K8sModelCommon } from '@openshift/dynamic-plugin-sdk-utils'; + +export const ConfigMapModel: K8sModelCommon = { + apiVersion: 'v1', + kind: 'ConfigMap', + plural: 'configmaps', +}; + +export const EventModel: K8sModelCommon = { + apiVersion: 'v1', + kind: 'Event', + plural: 'events', +}; + +export const PodModel: K8sModelCommon = { + apiVersion: 'v1', + kind: 'Pod', + plural: 'pods', +}; + +export const PVCModel: K8sModelCommon = { + apiVersion: 'v1', + kind: 'PersistentVolumeClaim', + plural: 'persistentvolumeclaims', +}; + +export const RoleBindingModel: K8sModelCommon = { + apiVersion: 'v1', + apiGroup: 'rbac.authorization.k8s.io', + kind: 'RoleBinding', + plural: 'rolebindings', +}; + +export const SecretModel: K8sModelCommon = { + apiVersion: 'v1', + kind: 'Secret', + plural: 'secrets', +}; diff --git a/frontend/src/api/models/odh.ts b/frontend/src/api/models/odh.ts new file mode 100644 index 0000000000..c6e1eeae39 --- /dev/null +++ b/frontend/src/api/models/odh.ts @@ -0,0 +1,15 @@ +import { K8sModelCommon } from '@openshift/dynamic-plugin-sdk-utils'; + +export const ODHDashboardConfigModel: K8sModelCommon = { + apiVersion: 'v1alpha', + apiGroup: 'opendatahub.io', + kind: 'ODHDashboardConfig', + plural: 'odhdashboardconfigs', +}; + +export const NotebookModel: K8sModelCommon = { + apiVersion: 'v1', + apiGroup: 'kubeflow.org', + kind: 'Notebook', + plural: 'notebooks', +}; diff --git a/frontend/src/api/models/openShift.ts b/frontend/src/api/models/openShift.ts new file mode 100644 index 0000000000..222f5ee02b --- /dev/null +++ b/frontend/src/api/models/openShift.ts @@ -0,0 +1,36 @@ +import { K8sModelCommon } from '@openshift/dynamic-plugin-sdk-utils'; + +export const BuildConfigModel: K8sModelCommon = { + apiVersion: 'v1', + apiGroup: 'build.openshift.io', + kind: 'BuildConfig', + plural: 'buildconfigs', +}; + +export const BuildModel: K8sModelCommon = { + apiVersion: 'v1', + apiGroup: 'build.openshift.io', + kind: 'Build', + plural: 'builds', +}; + +export const ImageStreamModel: K8sModelCommon = { + apiVersion: 'v1', + apiGroup: 'image.openshift.io', + kind: 'ImageStream', + plural: 'imagestreams', +}; + +export const ProjectModel: K8sModelCommon = { + apiVersion: 'v1', + apiGroup: 'project.openshift.io', + kind: 'Project', + plural: 'projects', +}; + +export const RouteModel: K8sModelCommon = { + apiVersion: 'v1', + apiGroup: 'route.openshift.io', + kind: 'Route', + plural: 'routes', +}; diff --git a/frontend/src/api/network/builds.ts b/frontend/src/api/network/builds.ts new file mode 100644 index 0000000000..2b784137d0 --- /dev/null +++ b/frontend/src/api/network/builds.ts @@ -0,0 +1,23 @@ +import { k8sListResource } from '@openshift/dynamic-plugin-sdk-utils'; +import { BuildConfigModel, BuildModel } from '../models'; +import { BuildConfigKind, BuildKind } from '../../k8sTypes'; + +export const getNotebookBuildConfigs = (namespace: string): Promise => { + return k8sListResource({ + model: BuildConfigModel, + queryOptions: { + ns: namespace, + queryParams: { labelSelector: 'opendatahub.io/build_type=notebook_image' }, + }, + }).then((r) => r.items); +}; + +export const getBuildsForBuildConfig = (namespace: string, name: string): Promise => { + return k8sListResource({ + model: BuildModel, + queryOptions: { + ns: namespace, + queryParams: { labelSelector: `buildconfig=${name}` }, + }, + }).then((r) => r.items); +}; diff --git a/frontend/src/api/network/configMaps.ts b/frontend/src/api/network/configMaps.ts new file mode 100644 index 0000000000..c06f835566 --- /dev/null +++ b/frontend/src/api/network/configMaps.ts @@ -0,0 +1,51 @@ +import { + k8sCreateResource, + k8sDeleteResource, + k8sGetResource, + k8sUpdateResource, +} from '@openshift/dynamic-plugin-sdk-utils'; +import { ConfigMapKind, K8sStatus } from '../../k8sTypes'; +import { ConfigMapModel } from '../models'; +import { genRandomChars } from '../../utilities/string'; + +export const assembleConfigMap = ( + projectName: string, + configMapData: Record, + configMapName?: string, +): ConfigMapKind => ({ + apiVersion: 'v1', + kind: 'ConfigMap', + metadata: { + name: configMapName || `configmap-${genRandomChars()}`, + namespace: projectName, + labels: { + 'opendatahub.io/dashboard': 'true', + }, + }, + data: configMapData, +}); + +export const getConfigMap = ( + projectName: string, + configMapName: string, +): Promise => { + return k8sGetResource({ + model: ConfigMapModel, + queryOptions: { name: configMapName, ns: projectName }, + }); +}; + +export const createConfigMap = (data: ConfigMapKind): Promise => { + return k8sCreateResource({ model: ConfigMapModel, resource: data }); +}; + +export const replaceConfigMap = (data: ConfigMapKind): Promise => { + return k8sUpdateResource({ model: ConfigMapModel, resource: data }); +}; + +export const deleteConfigMap = (projectName: string, configMapName: string): Promise => { + return k8sDeleteResource({ + model: ConfigMapModel, + queryOptions: { name: configMapName }, + }); +}; diff --git a/frontend/src/api/network/events.ts b/frontend/src/api/network/events.ts new file mode 100644 index 0000000000..020f84d0c7 --- /dev/null +++ b/frontend/src/api/network/events.ts @@ -0,0 +1,21 @@ +import { k8sListResource } from '@openshift/dynamic-plugin-sdk-utils'; +import { EventKind } from '../../k8sTypes'; +import { EventModel } from '../models'; + +export const getNotebookEvents = async ( + namespace: string, + podUid: string, +): Promise => { + return k8sListResource({ + model: EventModel, + queryOptions: { + ns: namespace, + queryParams: { + fieldSelector: `involvedObject.kind=Pod,involvedObject.uid=${podUid}`, + }, + }, + }).then( + // Filter the events by pods that have the same name as the notebook + (r) => r.items, + ); +}; diff --git a/frontend/src/api/network/imageStreams.ts b/frontend/src/api/network/imageStreams.ts new file mode 100644 index 0000000000..e3a13e2764 --- /dev/null +++ b/frontend/src/api/network/imageStreams.ts @@ -0,0 +1,13 @@ +import { k8sListResourceItems } from '@openshift/dynamic-plugin-sdk-utils'; +import { ImageStreamModel } from '../models'; +import { ImageStreamKind } from '../../k8sTypes'; + +export const getNotebookImageStreams = (namespace: string): Promise => { + return k8sListResourceItems({ + model: ImageStreamModel, + queryOptions: { + ns: namespace, + queryParams: { labelSelector: 'opendatahub.io/notebook-image=true' }, + }, + }); +}; diff --git a/frontend/src/api/network/notebooks.ts b/frontend/src/api/network/notebooks.ts new file mode 100644 index 0000000000..617ba93346 --- /dev/null +++ b/frontend/src/api/network/notebooks.ts @@ -0,0 +1,454 @@ +import { + k8sCreateResource, + k8sDeleteResource, + k8sGetResource, + k8sListResource, + k8sPatchResource, + k8sUpdateResource, + Patch, +} from '@openshift/dynamic-plugin-sdk-utils'; +import * as _ from 'lodash'; +import { NotebookModel } from '../models'; +import { K8sStatus, NotebookKind } from '../../k8sTypes'; +import { + NotebookAffinity, + NotebookResources, + NotebookToleration, + NotebookTolerationSettings, +} from '../../types'; +import { usernameTranslate } from '../../utilities/notebookControllerUtils'; +import { EnvironmentFromVariable, StartNotebookData } from '../../pages/projects/types'; +import { ROOT_MOUNT_PATH } from '../../pages/projects/pvc/const'; +import { translateDisplayNameForK8s } from '../../pages/projects/utils'; + +const assembleNotebookAffinityAndTolerations = ( + resources: NotebookResources, + gpus: number, + tolerationSettings?: NotebookTolerationSettings, +): { affinity: NotebookAffinity; tolerations: NotebookToleration[] } => { + let affinity: NotebookAffinity = {}; + const tolerations: NotebookToleration[] = []; + if (gpus > 0) { + if (!resources.limits) { + resources.limits = {}; + } + if (!resources.requests) { + resources.requests = {}; + } + resources.limits['nvidia.com/gpu'] = gpus; + resources.requests['nvidia.com/gpu'] = gpus; + tolerations.push({ + effect: 'NoSchedule', + key: 'nvidia.com/gpu', + operator: 'Exists', + }); + } else { + affinity = { + nodeAffinity: { + preferredDuringSchedulingIgnoredDuringExecution: [ + { + preference: { + matchExpressions: [ + { + key: 'nvidia.com/gpu.present', + operator: 'NotIn', + values: ['true'], + }, + ], + }, + weight: 1, + }, + ], + }, + }; + } + if (tolerationSettings?.enabled) { + tolerations.push({ + effect: 'NoSchedule', + key: tolerationSettings.key, + operator: 'Exists', + }); + } + return { affinity, tolerations }; +}; + +const assembleNotebook = (data: StartNotebookData, username: string): NotebookKind => { + const { + projectName, + notebookName, + notebookId: overrideNotebookId, + description, + notebookSize, + envFrom, + gpus, + image, + volumes, + volumeMounts, + tolerationSettings, + } = data; + const notebookId = overrideNotebookId || translateDisplayNameForK8s(notebookName); + const resources: NotebookResources = { ...notebookSize.resources }; + const imageUrl = `${image.imageStream?.status?.dockerImageRepository}:${image.imageVersion?.name}`; + const imageSelection = `${image.imageStream?.metadata.name}:${image.imageVersion?.name}`; + + const { affinity, tolerations } = assembleNotebookAffinityAndTolerations( + resources, + gpus, + tolerationSettings, + ); + + const translatedUsername = usernameTranslate(username); + + const location = new URL(window.location.href); + const origin = location.origin; + + return { + apiVersion: 'kubeflow.org/v1', + kind: 'Notebook', + metadata: { + labels: { + app: notebookId, + 'opendatahub.io/odh-managed': 'true', + 'opendatahub.io/user': translatedUsername, + 'opendatahub.io/dashboard': 'true', + }, + annotations: { + 'openshift.io/display-name': notebookName, + 'openshift.io/description': description || '', + 'notebooks.opendatahub.io/oauth-logout-url': `${origin}/notebookController/${translatedUsername}/home`, + 'notebooks.opendatahub.io/last-size-selection': notebookSize.name, + 'notebooks.opendatahub.io/last-image-selection': imageSelection, + 'opendatahub.io/username': username, + }, + name: notebookId, + namespace: projectName, + }, + spec: { + template: { + spec: { + affinity, + enableServiceLinks: false, + containers: [ + { + image: imageUrl, + imagePullPolicy: 'Always', + workingDir: ROOT_MOUNT_PATH, + name: notebookId, + env: [ + { + name: 'NOTEBOOK_ARGS', + value: `--ServerApp.port=8888 + --ServerApp.token='' + --ServerApp.password='' + --ServerApp.base_url=/notebook/${projectName}/${notebookId} + --ServerApp.quit_button=False + --ServerApp.tornado_settings={"user":"${translatedUsername}","hub_host":"${origin}","hub_prefix":"/notebookController/${translatedUsername}"}`, + }, + { + name: 'JUPYTER_IMAGE', + value: imageUrl, + }, + ], + envFrom, + resources, + volumeMounts, + ports: [ + { + name: 'notebook-port', + containerPort: 8888, + protocol: 'TCP', + }, + ], + livenessProbe: { + initialDelaySeconds: 10, + periodSeconds: 5, + timeoutSeconds: 1, + successThreshold: 1, + failureThreshold: 3, + httpGet: { + scheme: 'HTTP', + path: `/notebook/${projectName}/${notebookId}/api`, + port: 'notebook-port', + }, + }, + readinessProbe: { + initialDelaySeconds: 10, + periodSeconds: 5, + timeoutSeconds: 1, + successThreshold: 1, + failureThreshold: 3, + httpGet: { + scheme: 'HTTP', + path: `/notebook/${projectName}/${notebookId}/api`, + port: 'notebook-port', + }, + }, + }, + ], + volumes, + tolerations, + }, + }, + }, + }; +}; + +const getStopPatchDataString = (): string => new Date().toISOString().replace(/\.\d{3}Z/i, 'Z'); + +const startPatch: Patch = { + op: 'remove', + path: '/metadata/annotations/kubeflow-resource-stopped', +}; +const getStopPatch = (): Patch => ({ + op: 'add', + path: '/metadata/annotations/kubeflow-resource-stopped', + value: getStopPatchDataString(), +}); + +export const getNotebooks = (namespace: string): Promise => { + return k8sListResource({ + model: NotebookModel, + queryOptions: { ns: namespace }, + }).then((listResource) => listResource.items); +}; + +export const getNotebook = (name: string, namespace: string): Promise => { + return k8sGetResource({ + model: NotebookModel, + queryOptions: { name, ns: namespace }, + }); +}; + +export const stopNotebook = (name: string, namespace: string): Promise => { + return k8sPatchResource({ + model: NotebookModel, + queryOptions: { name, ns: namespace }, + patches: [getStopPatch()], + }); +}; + +export const startNotebook = (name: string, namespace: string): Promise => { + return k8sPatchResource({ + model: NotebookModel, + queryOptions: { name, ns: namespace }, + patches: [startPatch], + }); +}; + +export const createNotebook = ( + data: StartNotebookData, + username: string, +): Promise => { + const notebook = assembleNotebook(data, username); + + return k8sCreateResource({ + model: NotebookModel, + resource: notebook, + }); +}; + +export const updateNotebook = ( + existingNotebook: NotebookKind, + data: StartNotebookData, + username: string, +): Promise => { + data.notebookId = existingNotebook.metadata.name; + const notebook = assembleNotebook(data, username); + + return k8sUpdateResource({ + model: NotebookModel, + resource: _.merge({}, existingNotebook, notebook), + }); +}; + +export const createNotebookWithoutStarting = ( + data: StartNotebookData, + username: string, +): Promise => { + return new Promise((resolve, reject) => + createNotebook(data, username).then((notebook) => + setTimeout( + () => + stopNotebook(notebook.metadata.name, notebook.metadata.namespace) + .then(resolve) + .catch(reject), + 10_000, + ), + ), + ); +}; + +export const deleteNotebook = (notebookName: string, namespace: string): Promise => { + return k8sDeleteResource({ + model: NotebookModel, + queryOptions: { name: notebookName, ns: namespace }, + }); +}; + +export const attachNotebookSecret = ( + notebookName: string, + namespace: string, + secretName: string, + hasExistingEnvFrom: boolean, +): Promise => { + const patches: Patch[] = []; + + if (!hasExistingEnvFrom) { + // Create the array if it does not exist + patches.push({ + op: 'add', + // TODO: can we assume first container? + path: '/spec/template/spec/containers/0/envFrom', + value: [], + }); + } + + patches.push({ + op: 'add', + // TODO: can we assume first container? + path: '/spec/template/spec/containers/0/envFrom/-', + value: { + secretRef: { + name: secretName, + }, + }, + }); + + return k8sPatchResource({ + model: NotebookModel, + queryOptions: { name: notebookName, ns: namespace }, + patches, + }); +}; + +export const replaceNotebookSecret = ( + notebookName: string, + namespace: string, + newEnvs: EnvironmentFromVariable[], +): Promise => { + const patches: Patch[] = [ + { + op: 'replace', + // TODO: can we assume first container? + path: '/spec/template/spec/containers/0/envFrom', + value: newEnvs, + }, + ]; + + return k8sPatchResource({ + model: NotebookModel, + queryOptions: { name: notebookName, ns: namespace }, + patches, + }); +}; + +export const attachNotebookPVC = ( + notebookName: string, + namespace: string, + pvcName: string, + mountSuffix: string, +): Promise => { + const patches: Patch[] = [ + { + op: 'add', + path: '/spec/template/spec/volumes/-', + value: { name: pvcName, persistentVolumeClaim: { claimName: pvcName } }, + }, + { + op: 'add', + // TODO: can we assume first container? + path: '/spec/template/spec/containers/0/volumeMounts/-', + value: { mountPath: `${ROOT_MOUNT_PATH}/${mountSuffix}`, name: pvcName }, + }, + ]; + + return k8sPatchResource({ + model: NotebookModel, + queryOptions: { name: notebookName, ns: namespace }, + patches, + }); +}; + +export const removeNotebookPVC = ( + notebookName: string, + namespace: string, + pvcName: string, +): Promise => { + return new Promise((resolve, reject) => { + getNotebook(notebookName, namespace) + .then((notebook) => { + const volumes = notebook.spec.template.spec.volumes || []; + // TODO: can we assume first container? + const volumeMounts = notebook.spec.template.spec.containers[0].volumeMounts || []; + const filteredVolumes = volumes.filter( + (volume) => volume.persistentVolumeClaim?.claimName !== pvcName, + ); + const filteredVolumeMounts = volumeMounts.filter( + (volumeMount) => volumeMount.name !== pvcName, + ); + + const patches: Patch[] = [ + { + op: 'replace', + path: '/spec/template/spec/volumes', + value: + filteredVolumes.length === 0 + ? [{ name: 'cache-volume', emptyDir: {} }] + : filteredVolumes, + }, + { + op: 'replace', + // TODO: can we assume first container? + path: '/spec/template/spec/containers/0/volumeMounts', + value: + filteredVolumeMounts.length === 0 + ? [{ mountPath: '/cache', name: 'cache-volume' }] + : filteredVolumeMounts, + }, + ]; + + k8sPatchResource({ + model: NotebookModel, + queryOptions: { name: notebookName, ns: namespace }, + patches, + }) + .then(resolve) + .catch(reject); + }) + .catch(reject); + }); +}; + +export const removeNotebookSecret = ( + notebookName: string, + namespace: string, + secretName: string, +): Promise => { + return new Promise((resolve, reject) => { + getNotebook(notebookName, namespace) + .then((notebook) => { + const envFroms = notebook.spec.template.spec.containers[0].envFrom || []; + const filteredEnvFroms = envFroms.filter( + (envFrom) => envFrom.secretRef?.name !== secretName, + ); + + const patches: Patch[] = [ + { + op: 'replace', + // TODO: can we assume first container? + path: '/spec/template/spec/containers/0/envFrom', + value: filteredEnvFroms, + }, + ]; + + k8sPatchResource({ + model: NotebookModel, + queryOptions: { name: notebookName, ns: namespace }, + patches, + }) + .then(resolve) + .catch(reject); + }) + .catch(reject); + }); +}; diff --git a/frontend/src/api/network/pods.ts b/frontend/src/api/network/pods.ts new file mode 100644 index 0000000000..fe664712a5 --- /dev/null +++ b/frontend/src/api/network/pods.ts @@ -0,0 +1,13 @@ +import { k8sListResource } from '@openshift/dynamic-plugin-sdk-utils'; +import { PodModel } from '../models'; +import { PodKind } from '../../k8sTypes'; + +export const getPodsForNotebook = (namespace: string, notebookName: string): Promise => { + return k8sListResource({ + model: PodModel, + queryOptions: { + ns: namespace, + queryParams: { labelSelector: `notebook-name=${notebookName}` }, + }, + }).then((r) => r.items); +}; diff --git a/frontend/src/api/network/projects.ts b/frontend/src/api/network/projects.ts new file mode 100644 index 0000000000..3722d22347 --- /dev/null +++ b/frontend/src/api/network/projects.ts @@ -0,0 +1,108 @@ +import { + k8sCreateResource, + k8sDeleteResource, + k8sGetResource, + k8sListResource, + K8sModelCommon, + k8sUpdateResource, +} from '@openshift/dynamic-plugin-sdk-utils'; +import { ProjectKind } from '../../k8sTypes'; +import { usernameTranslate } from '../../utilities/notebookControllerUtils'; +import { ProjectModel } from '../models'; +import { translateDisplayNameForK8s } from '../../pages/projects/utils'; + +export const getProject = (projectName: string): Promise => { + return k8sGetResource({ + model: ProjectModel, + queryOptions: { name: projectName }, + }); +}; + +export const getProjects = (labelSelector?: string): Promise => { + const queryOptions = labelSelector ? { queryParams: { labelSelector } } : undefined; + return k8sListResource({ + model: ProjectModel, + queryOptions, + }).then((listResource) => listResource.items); +}; + +export const createProject = ( + username: string, + name: string, + description: string, + k8sName?: string, +): Promise => { + const translatedUsername = usernameTranslate(username); + + // Specific types and models for creating projects + const NamespaceModel: K8sModelCommon = { + apiVersion: 'v1', + kind: 'Namespace', + plural: 'namespaces', + }; + type NamespaceKind = ProjectKind & { + metadata: { + name: string; + }; + }; + + return new Promise((resolve, reject) => { + k8sCreateResource({ + model: NamespaceModel, + resource: { + apiVersion: 'v1', + kind: 'Namespace', + metadata: { + name: k8sName || translateDisplayNameForK8s(name), + annotations: { + 'openshift.io/description': description, + 'openshift.io/display-name': name, + 'openshift.io/requester': username, + }, + labels: { + 'opendatahub.io/dashboard': 'true', + 'opendatahub.io/user': translatedUsername, + }, + }, + }, + }) + .then((namespace) => { + if (!namespace) { + reject('Unable to create a project due to permissions.'); + return; + } + resolve(namespace.metadata.name); + }) + .catch(reject); + }); +}; + +export const updateProject = ( + editProjectData: ProjectKind, + displayName: string, + description: string, +): Promise => { + const resource: ProjectKind = { + ...editProjectData, + metadata: { + ...editProjectData.metadata, + annotations: { + ...editProjectData.metadata.annotations, + 'openshift.io/display-name': displayName, + 'openshift.io/description': description, + }, + }, + }; + + return k8sUpdateResource({ + model: ProjectModel, + resource, + }); +}; + +export const deleteProject = (projectName: string): Promise => { + return k8sDeleteResource({ + model: ProjectModel, + queryOptions: { name: projectName }, + }); +}; diff --git a/frontend/src/api/network/pvcs.ts b/frontend/src/api/network/pvcs.ts new file mode 100644 index 0000000000..e3690d5b74 --- /dev/null +++ b/frontend/src/api/network/pvcs.ts @@ -0,0 +1,120 @@ +import { + k8sCreateResource, + k8sDeleteResource, + k8sGetResource, + k8sListResourceItems, + k8sPatchResource, +} from '@openshift/dynamic-plugin-sdk-utils'; +import { K8sStatus, PersistentVolumeClaimKind } from '../../k8sTypes'; +import { PVCModel } from '../models'; +import { translateDisplayNameForK8s } from '../../pages/projects/utils'; + +export const assemblePvc = ( + pvcName: string, + projectName: string, + description: string, + pvcSize: number, +): PersistentVolumeClaimKind => { + return { + apiVersion: 'v1', + kind: 'PersistentVolumeClaim', + metadata: { + name: translateDisplayNameForK8s(pvcName), + namespace: projectName, + labels: { + 'opendatahub.io/dashboard': 'true', + }, + annotations: { + 'openshift.io/display-name': pvcName, + 'openshift.io/description': description, + }, + }, + spec: { + accessModes: ['ReadWriteOnce'], + resources: { + requests: { + storage: `${pvcSize}Gi`, + }, + }, + volumeMode: 'Filesystem', + }, + status: { + phase: 'Pending', + }, + }; +}; + +export const getPvc = ( + projectName: string, + pvcName: string, +): Promise => { + return k8sGetResource({ + model: PVCModel, + queryOptions: { name: pvcName, ns: projectName }, + }); +}; + +export const getPvcs = (projectName: string): Promise => { + return k8sListResourceItems({ + model: PVCModel, + queryOptions: { ns: projectName }, + }); +}; + +export const getAvailableMultiUsePvcs = ( + projectName: string, +): Promise => { + return getPvcs(projectName).then((pvcs) => + pvcs.filter((pvc) => { + const accessModes = pvc.spec.accessModes; + return accessModes.includes('ReadOnlyMany') || accessModes.includes('ReadWriteMany'); + }), + ); +}; + +export const createPvc = (data: PersistentVolumeClaimKind): Promise => { + return k8sCreateResource({ model: PVCModel, resource: data }); +}; + +export const updatePvcDisplayName = ( + pvcName: string, + namespace: string, + displayName: string, +): Promise => { + return k8sPatchResource({ + model: PVCModel, + queryOptions: { name: pvcName, ns: namespace }, + patches: [ + { + op: 'replace', + path: '/metadata/annotations/openshift.io~1display-name', + value: displayName, + }, + ], + }); +}; + +export const updatePvcDescription = ( + pvcName: string, + namespace: string, + description: string, +): Promise => { + return k8sPatchResource({ + model: PVCModel, + queryOptions: { name: pvcName, ns: namespace }, + patches: [ + { + op: 'replace', + path: '/metadata/annotations/openshift.io~1description', + value: description, + }, + ], + }); +}; + +export const deletePvc = (pvcName: string, namespace: string): Promise => { + return k8sDeleteResource({ + model: PVCModel, + queryOptions: { name: pvcName, ns: namespace }, + }); +}; diff --git a/frontend/src/api/network/roleBindings.ts b/frontend/src/api/network/roleBindings.ts new file mode 100644 index 0000000000..5babacfad3 --- /dev/null +++ b/frontend/src/api/network/roleBindings.ts @@ -0,0 +1,45 @@ +import { k8sCreateResource, k8sGetResource } from '@openshift/dynamic-plugin-sdk-utils'; +import { RoleBindingKind } from '../../k8sTypes'; +import { RoleBindingModel } from '../models'; + +export const generateRoleBindingData = ( + rbName: string, + dashboardNamespace: string, + projectName: string, +): RoleBindingKind => { + const roleBindingObject: RoleBindingKind = { + apiVersion: 'rbac.authorization.k8s.io/v1', + kind: 'RoleBinding', + metadata: { + name: rbName, + namespace: dashboardNamespace, + labels: { + 'opendatahub.io/dashboard': 'true', + }, + }, + roleRef: { + apiGroup: 'rbac.authorization.k8s.io', + kind: 'ClusterRole', + name: 'system:image-puller', + }, + subjects: [ + { + apiGroup: 'rbac.authorization.k8s.io', + kind: 'Group', + name: `system:serviceaccounts:${projectName}`, + }, + ], + }; + return roleBindingObject; +}; + +export const getRoleBinding = (projectName: string, rbName: string): Promise => { + return k8sGetResource({ + model: RoleBindingModel, + queryOptions: { name: rbName, ns: projectName }, + }); +}; + +export const createRoleBinding = (data: RoleBindingKind): Promise => { + return k8sCreateResource({ model: RoleBindingModel, resource: data }); +}; diff --git a/frontend/src/api/network/routes.ts b/frontend/src/api/network/routes.ts new file mode 100644 index 0000000000..ee63f1aece --- /dev/null +++ b/frontend/src/api/network/routes.ts @@ -0,0 +1,7 @@ +import { k8sGetResource } from '@openshift/dynamic-plugin-sdk-utils'; +import { RouteModel } from '../models'; +import { RouteKind } from '../../k8sTypes'; + +export const getRoute = (name: string, namespace: string): Promise => { + return k8sGetResource({ model: RouteModel, queryOptions: { name, ns: namespace } }); +}; diff --git a/frontend/src/api/network/secrets.ts b/frontend/src/api/network/secrets.ts new file mode 100644 index 0000000000..8f7d4a4d9f --- /dev/null +++ b/frontend/src/api/network/secrets.ts @@ -0,0 +1,74 @@ +import { + k8sCreateResource, + k8sDeleteResource, + k8sGetResource, + k8sListResource, + k8sUpdateResource, +} from '@openshift/dynamic-plugin-sdk-utils'; +import { K8sStatus, SecretKind } from '../../k8sTypes'; +import { SecretModel } from '../models'; +import { genRandomChars } from '../../utilities/string'; +import { translateDisplayNameForK8s } from '../../pages/projects/utils'; + +export const assembleSecret = ( + projectName: string, + data: Record, + type: 'aws' | 'generic' = 'generic', +): SecretKind => { + const labels = { + 'opendatahub.io/dashboard': 'true', + }; + const annotations = {}; + + let stringData = data; + let name = `secret-${genRandomChars()}`; + + if (type === 'aws') { + const { Name, ...secretBody } = data; + stringData = secretBody; + name = `aws-connection-${translateDisplayNameForK8s(Name)}`; + annotations['openshift.io/display-name'] = Name; + labels['opendatahub.io/managed'] = 'true'; + } + + return { + apiVersion: 'v1', + kind: 'Secret', + metadata: { + name, + namespace: projectName, + annotations, + labels, + }, + stringData, + }; +}; + +export const getSecret = (projectName: string, secretName: string): Promise => { + return k8sGetResource({ + model: SecretModel, + queryOptions: { name: secretName, ns: projectName }, + }); +}; + +export const getSecretsByLabel = (label: string, namespace: string): Promise => { + return k8sListResource({ + model: SecretModel, + queryOptions: { ns: namespace, queryParams: { labelSelector: label } }, + }).then((result) => result.items); +}; + +export const createSecret = (data: SecretKind): Promise => { + return k8sCreateResource({ model: SecretModel, resource: data }); +}; + +export const replaceSecret = (data: SecretKind): Promise => { + return k8sUpdateResource({ model: SecretModel, resource: data }); +}; + +export const deleteSecret = (projectName: string, secretName: string): Promise => { + return k8sDeleteResource({ + model: SecretModel, + queryOptions: { name: secretName, ns: projectName }, + }); +}; diff --git a/frontend/src/api/prometheus/pvcs.ts b/frontend/src/api/prometheus/pvcs.ts new file mode 100644 index 0000000000..bf60ab6d56 --- /dev/null +++ b/frontend/src/api/prometheus/pvcs.ts @@ -0,0 +1,28 @@ +import * as React from 'react'; +import usePrometheusQuery from './usePrometheusQuery'; +import { PersistentVolumeClaimKind } from '../../k8sTypes'; +import { POLL_INTERVAL } from '../../utilities/const'; + +export const usePVCFreeAmount = ( + pvc: PersistentVolumeClaimKind, +): [bytesInUse: number | typeof NaN, loaded: boolean, error: Error | undefined] => { + const [result, loaded, loadError, refetch] = usePrometheusQuery( + pvc.metadata.namespace, + `kubelet_volume_stats_used_bytes{persistentvolumeclaim='${pvc.metadata.name}'}`, + ); + + React.useEffect(() => { + const interval = setInterval(() => { + refetch(); + }, POLL_INTERVAL); + + return () => { + clearInterval(interval); + }; + }, [refetch]); + + const value = result?.data.result[0]?.value[1]; + const usedInBytes = parseInt(value || '', 10); + + return [usedInBytes, loaded, loadError]; +}; diff --git a/frontend/src/api/prometheus/usePrometheusQuery.ts b/frontend/src/api/prometheus/usePrometheusQuery.ts new file mode 100644 index 0000000000..cfb0dfd8a5 --- /dev/null +++ b/frontend/src/api/prometheus/usePrometheusQuery.ts @@ -0,0 +1,41 @@ +import * as React from 'react'; +import axios from 'axios'; +import { PrometheusResponse } from '../../types'; + +const usePrometheusQuery = ( + namespace: string, + query: string, +): [ + result: PrometheusResponse | null, + loaded: boolean, + loadError: Error | undefined, + refetch: () => void, +] => { + const [result, setResult] = React.useState(null); + const [loaded, setLoaded] = React.useState(false); + const [error, setError] = React.useState(); + + const fetchData = React.useCallback(() => { + if (!namespace || !query) return; + + const path = '/api/prometheus'; + axios + .post(path, { query, namespace }) + .then((response) => { + setResult(response.data.response); + setLoaded(true); + setError(undefined); + }) + .catch((e) => { + setError(e); + }); + }, [namespace, query]); + + React.useEffect(() => { + fetchData(); + }, [fetchData]); + + return [result, loaded, error, fetchData]; +}; + +export default usePrometheusQuery; diff --git a/frontend/src/app/App.tsx b/frontend/src/app/App.tsx index e31d6cf664..ddf75d6cdf 100644 --- a/frontend/src/app/App.tsx +++ b/frontend/src/app/App.tsx @@ -111,6 +111,7 @@ const App: React.FC = () => { sidebar={} notificationDrawer={ setNotificationsOpen(false)} />} isNotificationDrawerExpanded={notificationsOpen} + mainContainerId="dashboard-page-main" > diff --git a/frontend/src/app/AppRoutes.tsx b/frontend/src/app/AppRoutes.tsx index 6935f773f0..abc04a3ba0 100644 --- a/frontend/src/app/AppRoutes.tsx +++ b/frontend/src/app/AppRoutes.tsx @@ -12,6 +12,7 @@ const ExploreApplications = React.lazy( const NotebookLogoutRedirectPage = React.lazy( () => import('../pages/notebookController/NotebookLogoutRedirect'), ); +const ProjectViewRoutes = React.lazy(() => import('../pages/projects/ProjectViewRoutes')); const NotebookController = React.lazy( () => import('../pages/notebookController/NotebookController'), ); @@ -33,6 +34,7 @@ const AppRoutes: React.FC = () => { } /> } /> } /> + {isAllowed && } />} {isAllowed && } />} {isAllowed && ( = ({ item, pathname }) => { - const { children, group } = item; - const isGroup = group !== undefined; - const isActive = - group && children ? !!children.find((c) => pathname === c.href) : pathname === item.href; - const [expanded, setExpanded] = React.useState(isGroup && isActive); +const NavHref: React.FC<{ item: NavDataHref; pathname: string }> = ({ item, pathname }) => ( + + + {item.label} + + +); + +const NavGroup: React.FC<{ item: NavDataGroup; pathname: string }> = ({ item, pathname }) => { + const { group, children } = item; + const isActive = !!children.find((c) => pathname === c.href); + const [expanded, setExpanded] = React.useState(isActive); - if (group && children?.length) { - return ( - setExpanded(val)} - aria-label={group.title} - > - {children.map((childItem) => ( - - ))} - - ); - } return ( - - - {item.label} - - + setExpanded(val)} + aria-label={group.title} + > + {children.map((childItem) => ( + + ))} + ); }; @@ -53,9 +45,13 @@ const NavSidebar: React.FC = () => { const nav = ( ); diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 595568ca98..f4b0352007 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -4,6 +4,7 @@ import { BrowserRouter as Router } from 'react-router-dom'; import { Provider } from 'react-redux'; import { store } from './redux/store/store'; import App from './app/App'; +import SDKInitialize from './SDKInitialize'; /** /** @@ -13,7 +14,9 @@ ReactDOM.render( - + + + , diff --git a/frontend/src/k8sTypes.ts b/frontend/src/k8sTypes.ts new file mode 100644 index 0000000000..7503f9401b --- /dev/null +++ b/frontend/src/k8sTypes.ts @@ -0,0 +1,262 @@ +import { K8sResourceCommon } from '@openshift/dynamic-plugin-sdk-utils'; +import { NotebookAffinity, NotebookContainer, NotebookToleration, Volume } from './types'; + +/** + * Annotations that we will use to allow the user flexibility in describing items outside of the + * k8s structure. + */ +type DisplayNameAnnotations = Partial<{ + 'openshift.io/description': string; // the description provided by the user + 'openshift.io/display-name': string; // the name provided by the user +}>; + +export type K8sDSGResource = K8sResourceCommon & { + metadata: { + annotations?: DisplayNameAnnotations; + name: string; + }; +}; + +type ImageStreamAnnotations = Partial<{ + 'opendatahub.io/notebook-image-desc': string; + 'opendatahub.io/notebook-image-name': string; + 'opendatahub.io/notebook-image-url': string; + 'opendatahub.io/notebook-image-order': string; +}>; + +type ImageStreamSpecTagAnnotations = Partial<{ + 'opendatahub.io/notebook-python-dependencies': string; + 'opendatahub.io/notebook-software': string; + 'opendatahub.io/notebook-image-recommended': string; + 'opendatahub.io/default-image': string; +}>; + +export type NotebookAnnotations = Partial<{ + 'kubeflow-resource-stopped': string | null; // datestamp of stop (if omitted, it is running), `odh-notebook-controller-lock` is set when first creating the notebook to avoid race conditions, it's a fake stop + 'notebooks.kubeflow.org/last-activity': string; // datestamp of last use + 'opendatahub.io/link': string; // redirect notebook url + 'opendatahub.io/username': string; // the untranslated username behind the notebook + 'notebooks.opendatahub.io/last-image-selection': string; // the last image they selected + 'notebooks.opendatahub.io/last-size-selection': string; // the last notebook size they selected +}>; + +export type BuildConfigKind = K8sResourceCommon & { + metadata: { + name: string; + labels?: Partial<{ + 'opendatahub.io/notebook-name': string; + }>; + }; + spec: { + output: { + to: { + name: string; + }; + }; + }; +}; + +export type BuildKind = K8sResourceCommon & { + metadata: { + name: string; + annotations?: Partial<{ + 'openshift.io/build.number': string; + }>; + labels?: Partial<{ + buildconfig: string; + 'openshift.io/build-config.name': string; + }>; + }; + spec: { + output: { + to: { + name: string; + }; + }; + }; + status: { + phase: BUILD_PHASE; + completionTimestamp?: string; + startTimestamp?: string; + }; +}; + +/** + * Contains all the phases for BuildKind -> status -> phase (excluding NONE phase) + */ +export enum BUILD_PHASE { + NONE = 'Not started', + NEW = 'New', + RUNNING = 'Running', + PENDING = 'Pending', + COMPLETE = 'Complete', + FAILED = 'Failed', + ERROR = 'Error', + CANCELLED = 'Cancelled', +} + +export type ConfigMapKind = K8sResourceCommon & { + metadata: { + name: string; + }; + data?: Record; +}; + +export type EventKind = K8sResourceCommon & { + metadata: { + uid?: string; + }; + involvedObject: { + name: string; + }; + lastTimestamp?: string; + eventTime: string; + type: 'Normal' | 'Warning'; + reason: string; + message: string; +}; + +export type ImageStreamKind = K8sResourceCommon & { + metadata: { + annotations?: ImageStreamAnnotations; + name: string; + }; + spec: { + tags?: ImageStreamSpecTagType[]; + }; + status?: { + dockerImageRepository?: string; + publicDockerImageRepository?: string; + tags?: { + tag: string; + }[]; + }; +}; + +export type ImageStreamSpecTagType = { + name: string; + annotations?: ImageStreamSpecTagAnnotations; + from: { + kind: string; + name: string; + }; +}; + +/** A status object when Kube backend can't handle a request. */ +export type K8sStatus = { + kind: string; + apiVersion: string; + code: number; + message: string; + reason: string; + status: string; +}; + +export type PersistentVolumeClaimKind = K8sResourceCommon & { + metadata: { + annotations?: DisplayNameAnnotations; + name: string; + namespace: string; + }; + spec: { + accessModes: string[]; + resources: { + requests: { + storage: string; + }; + }; + storageClassName?: string; + volumeMode: 'Filesystem' | 'Block'; + }; + status?: { + phase: string; + capacity?: { + storage: string; + }; + } & Record; +}; + +export type NotebookKind = K8sResourceCommon & { + metadata: { + annotations: DisplayNameAnnotations & NotebookAnnotations; + name: string; + namespace: string; + labels: Partial<{ + 'opendatahub.io/user': string; // translated username -- see translateUsername + }>; + }; + spec: { + template: { + spec: { + affinity?: NotebookAffinity; + enableServiceLinks?: boolean; + containers: NotebookContainer[]; + volumes?: Volume[]; + tolerations?: NotebookToleration[]; + }; + }; + }; + status?: { + containerState?: { + terminated?: { [key: string]: string }; + }; + }; +}; + +export type PodKind = K8sResourceCommon & { + status: { + containerStatuses: { ready: boolean; state?: { running?: boolean } }[]; + }; +}; + +export type ProjectKind = K8sResourceCommon & { + metadata: { + annotations?: DisplayNameAnnotations & + Partial<{ + 'openshift.io/requester': string; // the username of the user that requested this project + }>; + labels?: Partial<{ + 'opendatahub.io/user': string; // translated username -- see translateUsername + }>; + name: string; + }; + status?: { + phase: 'Active' | 'Terminating'; + }; +}; + +type RoleBindingSubject = { + kind: string; + apiGroup: string; + name: string; +}; + +export type RoleBindingKind = K8sResourceCommon & { + subjects: RoleBindingSubject[]; + roleRef: RoleBindingSubject; +}; + +export type RouteKind = K8sResourceCommon & { + spec: { + host: string; + }; +}; + +export type SecretKind = K8sResourceCommon & { + metadata: { + name: string; + namespace: string; + }; + data?: Record; + stringData?: Record; + type?: string; +}; + +export type AWSSecretKind = SecretKind & { + metadata: { + annotations?: DisplayNameAnnotations; + labels?: { + 'opendatahub.io/managed': 'true'; + }; + }; +}; diff --git a/frontend/src/pages/ApplicationsPage.scss b/frontend/src/pages/ApplicationsPage.scss index d5804dcb9b..66efb5f3d4 100644 --- a/frontend/src/pages/ApplicationsPage.scss +++ b/frontend/src/pages/ApplicationsPage.scss @@ -1,5 +1,8 @@ .odh-apps { &__heading { + .pf-c-breadcrumb { + margin-bottom: var(--pf-global--spacer--md); + } &__text { margin-bottom: 1rem; } diff --git a/frontend/src/pages/ApplicationsPage.tsx b/frontend/src/pages/ApplicationsPage.tsx index a1bee7718c..3d2631ee3a 100644 --- a/frontend/src/pages/ApplicationsPage.tsx +++ b/frontend/src/pages/ApplicationsPage.tsx @@ -19,6 +19,7 @@ import './ApplicationsPage.scss'; type ApplicationsPageProps = { title: string; + breadcrumb?: React.ReactNode; description: React.ReactNode; loaded: boolean; empty: boolean; @@ -27,10 +28,12 @@ type ApplicationsPageProps = { emptyMessage?: string; emptyStatePage?: React.ReactNode; headerAction?: React.ReactNode; + provideChildrenPadding?: boolean; }; const ApplicationsPage: React.FC = ({ title, + breadcrumb, description, loaded, empty, @@ -40,20 +43,24 @@ const ApplicationsPage: React.FC = ({ emptyMessage, emptyStatePage, headerAction, + provideChildrenPadding, }) => { - const renderHeader = () => ( - - - - - {title} - {description} - - - {headerAction && {headerAction}} - - - ); + const renderHeader = () => { + return ( + + {breadcrumb} + + + + {title} + {description} + + + {headerAction && {headerAction}} + + + ); + }; const renderContents = () => { if (loadError) { @@ -102,6 +109,14 @@ const ApplicationsPage: React.FC = ({ ); } + if (provideChildrenPadding) { + return ( + + {children} + + ); + } + return children; }; diff --git a/frontend/src/pages/learningCenter/LearningCenter.tsx b/frontend/src/pages/learningCenter/LearningCenter.tsx index a510dafc12..2eb6e9ff88 100644 --- a/frontend/src/pages/learningCenter/LearningCenter.tsx +++ b/frontend/src/pages/learningCenter/LearningCenter.tsx @@ -85,10 +85,10 @@ export const LearningCenter: React.FC = () => { // Add doc cards for all quick starts qsContext.allQuickStarts?.forEach((quickStart) => { - const odhDoc: OdhDocument = _.merge({}, quickStart, { + const odhDoc = _.merge({}, quickStart, { spec: { type: OdhDocumentType.QuickStart }, }); - docs.push(odhDoc); + docs.push(odhDoc as unknown as OdhDocument); // TODO: Fix QuickStart type dependency -- they updated their types and broke us }); const updatedDocApps = docs diff --git a/frontend/src/pages/notebookController/screens/admin/UserTableCellTransform.tsx b/frontend/src/pages/notebookController/screens/admin/UserTableCellTransform.tsx index 6f3d27be20..5d275d0fe2 100644 --- a/frontend/src/pages/notebookController/screens/admin/UserTableCellTransform.tsx +++ b/frontend/src/pages/notebookController/screens/admin/UserTableCellTransform.tsx @@ -6,7 +6,7 @@ import NotebookActions from './NotebookActions'; type TableDataRendererProps = { user: AdminViewUserData; - userProperty: keyof AdminViewUserData; + userProperty: string; //keyof AdminViewUserData; }; const UserTableCellTransform: React.FC = ({ user, userProperty }) => { diff --git a/frontend/src/pages/notebookController/screens/server/SpawnerPage.tsx b/frontend/src/pages/notebookController/screens/server/SpawnerPage.tsx index f9263a919b..d86fc905a4 100644 --- a/frontend/src/pages/notebookController/screens/server/SpawnerPage.tsx +++ b/frontend/src/pages/notebookController/screens/server/SpawnerPage.tsx @@ -116,7 +116,11 @@ const SpawnerPage: React.FC = () => { } let fetchedVariableRows: VariableRow[] = []; const envVarFileName = generateEnvVarFileNameFromUsername(username); - const response = await verifyResource(envVarFileName, projectName, fetchFunc); + const response = await verifyResource( + envVarFileName, + projectName, + fetchFunc, + ); if (response && response.data) { const isSecret = response.kind === EnvVarResourceType.Secret; fetchedVariableRows = Object.entries(response.data).map(([key, value]) => { diff --git a/frontend/src/pages/notebookController/screens/server/StopServerModal.tsx b/frontend/src/pages/notebookController/screens/server/StopServerModal.tsx index 28ffa7f7af..b6554eb7e1 100644 --- a/frontend/src/pages/notebookController/screens/server/StopServerModal.tsx +++ b/frontend/src/pages/notebookController/screens/server/StopServerModal.tsx @@ -33,13 +33,12 @@ const StopServerModal: React.FC = ({ notebooksToStop, onNo }), ) .then(() => { + setDeleting(false); onNotebooksStop(true); }) .catch((e) => { - notification.error(`Error stopping ${textToShow}`, e.message); - }) - .finally(() => { setDeleting(false); + notification.error(`Error stopping ${textToShow}`, e.message); }); }; diff --git a/frontend/src/pages/notebookController/useNamespaces.ts b/frontend/src/pages/notebookController/useNamespaces.ts index 63421241c5..00ebd9f23d 100644 --- a/frontend/src/pages/notebookController/useNamespaces.ts +++ b/frontend/src/pages/notebookController/useNamespaces.ts @@ -1,10 +1,15 @@ import { useAppContext } from '../../app/AppContext'; import { useDashboardNamespace } from '../../redux/selectors'; -const useNamespaces = (): { notebookNamespace: string; dashboardNamespace: string } => { +const useNamespaces = (): { + /** @deprecated - all new functionality should use project creation under DSG */ + notebookNamespace: string; + dashboardNamespace: string; +} => { const { dashboardConfig } = useAppContext(); const { dashboardNamespace } = useDashboardNamespace(); + /** @deprecated */ const notebookNamespace = dashboardConfig.spec.notebookController?.notebookNamespace; return { notebookNamespace: notebookNamespace || dashboardNamespace, dashboardNamespace }; diff --git a/frontend/src/pages/projects/ProjectDetailsContext.tsx b/frontend/src/pages/projects/ProjectDetailsContext.tsx new file mode 100644 index 0000000000..9fcd44f37e --- /dev/null +++ b/frontend/src/pages/projects/ProjectDetailsContext.tsx @@ -0,0 +1,122 @@ +import * as React from 'react'; +import { PersistentVolumeClaimKind, ProjectKind } from '../../k8sTypes'; +import { Outlet, useParams } from 'react-router-dom'; +import { + Bullseye, + Button, + EmptyState, + EmptyStateBody, + EmptyStateIcon, + Spinner, + Title, +} from '@patternfly/react-core'; +import useProject from './useProject'; +import { useNavigate } from 'react-router-dom'; +import { ExclamationCircleIcon } from '@patternfly/react-icons'; +import useProjectNotebookStates from './notebook/useProjectNotebookStates'; +import useProjectPvcs from './screens/detail/storage/useProjectPvcs'; +import useDataConnections from './screens/detail/data-connections/useDataConnections'; +import { DataConnection } from './types'; +import { NotebookState } from './notebook/types'; +import { POLL_INTERVAL } from '../../utilities/const'; + +type ContextResourceData = { + data: T[]; + loaded: boolean; + error?: Error; + refresh: () => void; +}; + +type ProjectDetailsContextType = { + currentProject: ProjectKind; + refreshAllProjectData: () => void; + notebooks: ContextResourceData; + pvcs: ContextResourceData; + dataConnections: ContextResourceData; +}; + +const DEFAULT_DATA: ContextResourceData = { + data: [], + loaded: false, + refresh: () => undefined, +}; + +const useContextResourceData = (resourceData): ContextResourceData => { + const [values, loaded, error, refresh] = resourceData; + React.useEffect(() => { + const timer = setInterval(() => refresh(), POLL_INTERVAL); + return () => clearInterval(timer); + }, [refresh]); + return React.useMemo( + () => ({ + data: values, + loaded, + error, + refresh, + }), + [error, loaded, refresh, values], + ); +}; + +export const ProjectDetailsContext = React.createContext({ + // We never will get into a case without a project, so fudge the default value + currentProject: null as unknown as ProjectKind, + refreshAllProjectData: () => undefined, + notebooks: DEFAULT_DATA, + pvcs: DEFAULT_DATA, + dataConnections: DEFAULT_DATA, +}); + +const ProjectDetailsContextProvider: React.FC = () => { + const navigate = useNavigate(); + const { namespace } = useParams<{ namespace: string }>(); + const [project, loaded, error] = useProject(namespace); + const notebooks = useContextResourceData(useProjectNotebookStates(namespace)); + const pvcs = useContextResourceData(useProjectPvcs(namespace)); + const dataConnections = useContextResourceData(useDataConnections(namespace)); + + const notebookRefresh = notebooks.refresh; + const pvcRefresh = pvcs.refresh; + const dataConnectionRefresh = dataConnections.refresh; + const refreshAllProjectData = React.useCallback(() => { + notebookRefresh(); + setTimeout(notebookRefresh, 2000); + pvcRefresh(); + dataConnectionRefresh(); + }, [notebookRefresh, pvcRefresh, dataConnectionRefresh]); + + if (error) { + return ( + + + + + Problem loading project details + + {error.message} + + + + ); + } + + if (!loaded || !project) { + return ( + + + + ); + } + + return ( + + + + ); +}; + +export default ProjectDetailsContextProvider; diff --git a/frontend/src/pages/projects/ProjectViewRoutes.tsx b/frontend/src/pages/projects/ProjectViewRoutes.tsx new file mode 100644 index 0000000000..6f32c87c7d --- /dev/null +++ b/frontend/src/pages/projects/ProjectViewRoutes.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import { Navigate, Routes, Route } from 'react-router-dom'; +import ProjectDetails from './screens/detail/ProjectDetails'; +import ProjectView from './screens/projects/ProjectView'; +import ProjectDetailsContextProvider from './ProjectDetailsContext'; +import SpawnerPage from './screens/spawner/SpawnerPage'; +import EditSpawnerPage from './screens/spawner/EditSpawnerPage'; + +const ProjectViewRoutes: React.FC = () => { + return ( + + } /> + }> + } /> + } /> + } /> + } /> + + } /> + + ); +}; + +export default ProjectViewRoutes; diff --git a/frontend/src/pages/projects/components/DeleteModal.tsx b/frontend/src/pages/projects/components/DeleteModal.tsx new file mode 100644 index 0000000000..224d7a9d93 --- /dev/null +++ b/frontend/src/pages/projects/components/DeleteModal.tsx @@ -0,0 +1,83 @@ +import * as React from 'react'; +import { Alert, Button, Modal, Stack, StackItem, TextInput } from '@patternfly/react-core'; + +type DeleteModalProps = { + title: string; + isOpen: boolean; + onClose: () => void; + deleting: boolean; + onDelete: () => void; + deleteName: string; + submitButtonLabel?: string; + error?: Error; +}; + +const DeleteModal: React.FC = ({ + children, + title, + isOpen, + onClose, + deleting, + onDelete, + deleteName, + error, + submitButtonLabel = 'Delete', +}) => { + const [value, setValue] = React.useState(''); + + const onBeforeClose = (deleted: boolean) => { + setValue(''); + + if (deleted) { + onDelete(); + } else { + onClose(); + } + }; + + return ( + onBeforeClose(false)} + actions={[ + , + , + ]} + variant="small" + > + + {children} + + Confirm deletion by typing {deleteName} below: + + + setValue(newValue)} + /> + + {error && ( + + + {error.message} + + + )} + + + ); +}; + +export default DeleteModal; diff --git a/frontend/src/pages/projects/components/DeleteModalConnectedAlert.tsx b/frontend/src/pages/projects/components/DeleteModalConnectedAlert.tsx new file mode 100644 index 0000000000..f2e305620e --- /dev/null +++ b/frontend/src/pages/projects/components/DeleteModalConnectedAlert.tsx @@ -0,0 +1,44 @@ +import * as React from 'react'; +import { NotebookKind } from '../../../k8sTypes'; +import { Alert } from '@patternfly/react-core'; +import { getNotebookDisplayName } from '../utils'; + +type DeleteModalConnectedAlertProps = { + loaded: boolean; + error?: Error; + connectedNotebooks: NotebookKind[]; +}; + +const DeleteModalConnectedAlert: React.FC = ({ + loaded, + error, + connectedNotebooks, +}) => { + const warning = 'This action cannot be undone.'; + if (!loaded) { + return <>{warning}; + } + if (error) { + + {error.message} + ; + } + return connectedNotebooks.length !== 0 ? ( + + This resource is connected to{' '} + {connectedNotebooks.map((notebook) => getNotebookDisplayName(notebook)).join(', ')} + + } + > + {`${warning} It will restart the workbenches it connects to.`} + + ) : ( + <>{warning} + ); +}; + +export default DeleteModalConnectedAlert; diff --git a/frontend/src/pages/projects/components/ExistingPVCField.tsx b/frontend/src/pages/projects/components/ExistingPVCField.tsx new file mode 100644 index 0000000000..51b2a8a564 --- /dev/null +++ b/frontend/src/pages/projects/components/ExistingPVCField.tsx @@ -0,0 +1,79 @@ +import * as React from 'react'; +import { Alert, FormGroup, Select, SelectOption } from '@patternfly/react-core'; +import { getPvcDisplayName } from '../utils'; +import { PersistentVolumeClaimKind } from '../../../k8sTypes'; + +type ExistingPVCFieldProps = { + fieldId: string; + storages: PersistentVolumeClaimKind[]; + loaded: boolean; + loadError?: Error; + selectedStorage?: string; + setStorage: (storage?: string) => void; + selectDirection?: 'up' | 'down'; + menuAppendTo?: HTMLElement | 'parent'; +}; + +const ExistingPVCField: React.FC = ({ + fieldId, + storages, + loaded, + loadError, + selectedStorage, + setStorage, + selectDirection = 'down', + menuAppendTo = 'parent', +}) => { + const [isOpen, setOpen] = React.useState(false); + + if (loadError) { + return ( + + {loadError.message} + + ); + } + + const empty = storages.length === 0; + let placeholderText: string; + if (!loaded) { + placeholderText = 'Loading storages...'; + } else if (empty) { + placeholderText = 'No existing storages available'; + } else { + placeholderText = 'Select a persistent storage'; + } + + return ( + + + + ); +}; + +export default ExistingPVCField; diff --git a/frontend/src/pages/projects/components/ExistingProjectField.tsx b/frontend/src/pages/projects/components/ExistingProjectField.tsx new file mode 100644 index 0000000000..6971d8efa0 --- /dev/null +++ b/frontend/src/pages/projects/components/ExistingProjectField.tsx @@ -0,0 +1,70 @@ +import * as React from 'react'; +import { Alert, FormGroup, Select, SelectOption, Skeleton } from '@patternfly/react-core'; +import { getProjectDisplayName } from '../utils'; +import useUserProjects from '../screens/projects/useUserProjects'; + +type ExistingProjectFieldProps = { + fieldId: string; + selectedProject?: string; + onSelect: (selection?: string) => void; + selectDirection?: 'up' | 'down'; + menuAppendTo?: HTMLElement | 'parent'; +}; + +const ExistingProjectField: React.FC = ({ + fieldId, + selectedProject, + onSelect, + selectDirection = 'down', + menuAppendTo = 'parent', +}) => { + const [isOpen, setOpen] = React.useState(false); + + const [projects, loaded, loadError] = useUserProjects(); + + if (!loaded) { + return ; + } + + if (loadError) { + return ( + + {loadError.message} + + ); + } + + const options = projects.map((project) => ( + + {getProjectDisplayName(project)} + + )); + + return ( + + + + ); +}; + +export default ExistingProjectField; diff --git a/frontend/src/pages/projects/components/GenericSidebar.tsx b/frontend/src/pages/projects/components/GenericSidebar.tsx new file mode 100644 index 0000000000..604162b85d --- /dev/null +++ b/frontend/src/pages/projects/components/GenericSidebar.tsx @@ -0,0 +1,42 @@ +import * as React from 'react'; +import { + JumpLinks, + JumpLinksItem, + Sidebar, + SidebarContent, + SidebarPanel, +} from '@patternfly/react-core'; + +type GenericSidebarProps = { + sections: string[]; + titles: Record; + scrollableSelector: string; + maxWidth?: number; +}; + +const GenericSidebar: React.FC = ({ + children, + sections, + titles, + scrollableSelector, + maxWidth, +}) => { + return ( + + + + {sections.map((section) => ( + + {titles[section]} + + ))} + + + + {children} + + + ); +}; + +export default GenericSidebar; diff --git a/frontend/src/pages/projects/components/IndentSection.tsx b/frontend/src/pages/projects/components/IndentSection.tsx new file mode 100644 index 0000000000..638686243c --- /dev/null +++ b/frontend/src/pages/projects/components/IndentSection.tsx @@ -0,0 +1,13 @@ +import * as React from 'react'; +import { Flex, FlexItem } from '@patternfly/react-core'; + +const IndentSection: React.FC = ({ children }) => { + return ( + + + {children} + + ); +}; + +export default IndentSection; diff --git a/frontend/src/pages/projects/components/NameDescriptionField.tsx b/frontend/src/pages/projects/components/NameDescriptionField.tsx new file mode 100644 index 0000000000..3f6bd484be --- /dev/null +++ b/frontend/src/pages/projects/components/NameDescriptionField.tsx @@ -0,0 +1,108 @@ +import * as React from 'react'; +import { FormGroup, Stack, StackItem, TextArea, TextInput, Tooltip } from '@patternfly/react-core'; +import { NameDescType } from '../types'; +import { isValidK8sName, translateDisplayNameForK8s } from '../utils'; +import { HelpIcon } from '@patternfly/react-icons'; + +type NameDescriptionFieldProps = { + nameFieldId: string; + descriptionFieldId: string; + data: NameDescType; + setData: (data: NameDescType) => void; + autoFocusName?: boolean; + showK8sName?: boolean; + disableK8sName?: boolean; +}; + +const NameDescriptionField: React.FC = ({ + nameFieldId, + descriptionFieldId, + data, + setData, + autoFocusName, + showK8sName, + disableK8sName, +}) => { + const autoSelectNameRef = React.useRef(null); + + React.useEffect(() => { + if (autoFocusName) { + autoSelectNameRef.current?.focus(); + } + }, [autoFocusName]); + + const k8sName = React.useMemo(() => translateDisplayNameForK8s(data.name), [data.name]); + + return ( + + + + setData({ ...data, name })} + /> + + + {showK8sName && ( + + + + Resource names are what your resources are labeled in OpenShift. + + Resource names are not editable after creation. + + } + > + + + } + isRequired + fieldId={nameFieldId} + helperText={ + !disableK8sName && + "Must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character" + } + > + { + setData({ ...data, k8sName }); + }} + validated={!isValidK8sName(data.k8sName) ? 'error' : undefined} + /> + + + )} + + +