diff --git a/app/services/minio.js b/app/services/minio.js new file mode 100644 index 0000000..d5802c7 --- /dev/null +++ b/app/services/minio.js @@ -0,0 +1,70 @@ +// minio.js +// Copyright (C) 2024 DTP Technologies, LLC +// All Rights Reserved + +'use strict'; + + +import * as Minio from 'minio'; + +import { SiteService } from '../../lib/site-lib.js'; + +export default class MinioService extends SiteService { + + static get name ( ) { return 'MinioService'; } + static get slug ( ) { return 'minio'; } + + constructor (dtp) { + super(dtp, MinioService); + } + + async start ( ) { + await super.start(); + + this.minio = new Minio.Client({ + endPoint: process.env.MINIO_ENDPOINT, + port: parseInt(process.env.MINIO_PORT, 10), + useSSL: (process.env.MINIO_USE_SSL === 'enabled'), + accessKey: process.env.MINIO_ACCESS_KEY, + secretKey: process.env.MINIO_SECRET_KEY, + }); + } + + async uploadFile (fileInfo) { + const result = await this.minio.fPutObject( + fileInfo.bucket, + fileInfo.key, + fileInfo.filePath, + fileInfo.metadata + ); + return result; + } + + async downloadFile (fileInfo) { + const obj = await this.minio.fGetObject(fileInfo.bucket, fileInfo.key, fileInfo.filePath); + return obj; + } + + async openDownloadStream (fi) { + if (fi.range) { + const length = fi.range.end - fi.range.start + 1; + const stream = await this.minio.getPartialObject(fi.bucket, fi.key, fi.range.start, length); + return stream; + } + const stream = await this.minio.getObject(fi.bucket, fi.key); + return stream; + } + + async removeObject (bucket, key) { + await this.minio.removeObject(bucket, key); + } + + async statObject (bucket, key) { + const stat = await this.minio.statObject(bucket, key); + return stat; + } + + async statFile (file) { + return await this.statObject(file.bucket, file.key); + } +} \ No newline at end of file diff --git a/dtp-chat.js b/dtp-chat.js index fdbaad0..5899c5d 100644 --- a/dtp-chat.js +++ b/dtp-chat.js @@ -21,16 +21,8 @@ import webpackDevMiddleware from 'webpack-dev-middleware'; import WEBPACK_CONFIG from './webpack.config.js'; -import numeral from 'numeral'; -import dayjs from 'dayjs'; -import * as Marked from 'marked'; -import hljs from 'highlight.js'; - -import mongoose from 'mongoose'; -import { Redis } from 'ioredis'; - -import { SiteLog } from './lib/site-lib.js'; import { SiteTripwire } from './lib/site-tripwire.js'; +import { SiteRuntime } from './lib/site-runtime.js'; import http from 'node:http'; @@ -40,174 +32,33 @@ import session from 'express-session'; import RedisStore from 'connect-redis'; import passport from 'passport'; -import { Emitter } from '@socket.io/redis-emitter'; - -const APP_CONFIG = { - pkg: require('./package.json'), -}; +class SiteWebApp extends SiteRuntime { -class Harness { - - static get name ( ) { return 'Harness'; } - static get slug ( ) { return 'harness'; } + static get name ( ) { return 'SiteWebApp'; } + static get slug ( ) { return 'webApp'; } constructor ( ) { - this.config = { root: __dirname }; - this.models = [ ]; - - this.log = new SiteLog(this, Harness); + super(SiteWebApp, __dirname); } async start ( ) { - await this.loadConfig(); + await super.start(); this.log.info('loading SiteTripwire (known-malicious request protection)'); this.tripwire = new SiteTripwire(this); await this.tripwire.start(); - await this.connectMongoDB(); - await this.connectRedis(); - - await this.loadModels(); - await this.loadServices(); await this.startExpressJS(); } - async loadConfig ( ) { - this.config.site = (await import('./config/site.js')).default; - this.config.limiter = (await import('./config/limiter.js')).default; - this.config.jobQueues = (await import('./config/job-queues.js')).default; - } - - async connectMongoDB ( ) { - try { - this.log.info('starting MongoDB'); - - /* - * For some time, strictQuery=true was the Mongoose default. It's being - * changed. The option has to be set manually now. - */ - mongoose.set('strictQuery', true); - - this.log.info('connecting to MongoDB database', { - pid: process.pid, - host: process.env.MONGODB_HOST, - database: process.env.MONGODB_DATABASE, - }); - const mongoConnectUri = `mongodb://${process.env.DTP_MONGODB_HOST}/${process.env.DTP_MONGODB_DATABASE}`; - await mongoose.connect(mongoConnectUri, { - socketTimeoutMS: 0, - dbName: process.env.MONGODB_DATABASE, - }); - this.db = mongoose.connection; - this.log.info('connected to MongoDB'); - } catch (error) { - this.log.error('failed to connect to database', { error }); - throw error; - } - } - - async loadModels ( ) { - const basePath = path.join(this.config.root, 'app', 'models'); - const entries = await fs.promises.readdir(basePath, { withFileTypes: true }); - - this.log.info('loading models', { count: entries.length }); - for (const entry of entries) { - if (!entry.isFile()) { - continue; - } - const filename = path.join(basePath, entry.name); - const model = (await import(filename)).default; - if (this.models[model.modelName]) { - this.log.error('model name collision', { name: model.modelName }); - process.exit(-1); - } - this.models.push(model); - this.log.info('model loaded', { name: model.modelName}); - } - } - - async resetIndexes (target) { - if (target === 'all') { - for (const model of this.models) { - await this.resetIndex(model); - } - return; - } - - const model = this.models.find((model) => model.modelName === target); - if (!model) { - throw new Error(`requested Mongoose model does not exist: ${target}`); - } - - return this.resetIndex(model); - } - - async resetIndex (model) { - return new Promise(async (resolve, reject) => { - this.log.info('dropping model indexes', { model: model.modelName }); - model.collection.dropIndexes((err) => { - if (err) { - return reject(err); - } - this.log.info('creating model indexes', { model: model.modelName }); - model.ensureIndexes((err) => { - if (err) { - return reject(err); - } - return resolve(model); - }); - }); - }); - } - - async connectRedis ( ) { - try { - const options = { - host: process.env.DTP_REDIS_HOST, - port: parseInt(process.env.DTP_REDIS_PORT || '6379', 10), - password: process.env.DTP_REDIS_PASSWORD, - keyPrefix: process.env.DTP_REDIS_KEY_PREFIX, - lazyConnect: false, - }; - this.log.info('connecting to Redis', { - host: options.host, - port: options.port, - prefix: options.keyPrefix || 'dtp', - }); - - this.redis = new Redis(options); - this.redis.setMaxListeners(64); // prevents warnings/errors with Bull Queue - - this.log.info('creating Socket.io Emitter'); - this.emitter = new Emitter(this.redis); - - this.log.info('Redis connected'); - } catch (error) { - this.log.error('failed to connect to Redis', error); - throw new Error('failed to connect to Redis', { cause: error }); - } - } - - async getRedisKeys (pattern) { - return new Promise((resolve, reject) => { - return this.redis.keys(pattern, (err, response) => { - if (err) { - return reject(err); - } - return resolve(response); - }); - }); - } - async startExpressJS ( ) { const { session: sessionService } = this.services; this.app = express(); - this.app.locals.config = APP_CONFIG; - this.app.locals.pkg = APP_CONFIG.pkg; // convenience - this.app.locals.site = (await import(path.join(this.config.root, 'config', 'site.js'))).default; + this.app.locals.config = this.config; + this.app.locals.pkg = this.config.pkg; + this.app.locals.site = this.config.site; this.app.set('view engine', 'pug'); this.app.set('views', path.join(__dirname, 'app', 'views')); @@ -367,46 +218,12 @@ class Harness { this.log.error('failed to start application services', { err }); return reject(new Error('failed to start application services', { cause: err })); } - this.log.info(`${APP_CONFIG.pkg.name} application services online.`); + this.log.info(`${this.config.pkg.name} application services online.`); return resolve(); }); }); } - async loadServices ( ) { - const basePath = path.join(this.config.root, 'app', 'services'); - const entries = await fs.promises.readdir(basePath, { withFileTypes: true }); - const inits = [ ]; - - this.services = { }; - - for await (const entry of entries) { - if (!entry.isFile()) { - continue; - } - try { - const ServiceClass = (await import(path.join(basePath, entry.name))).default; - this.log.info('loading service', { - script: entry.name, - name: ServiceClass.name, - slug: ServiceClass.slug, - }); - - const service = new ServiceClass(this); - - this.services[ServiceClass.slug] = service; - inits.push(service); - } catch (error) { - this.log.error('failed to load service', { error }); - throw new Error('failed to load service', { cause: error }); - } - } - - for await (const service of inits) { - await service.start(); - } - } - async loadControllers ( ) { const basePath = path.join(this.config.root, 'app', 'controllers'); const entries = await fs.promises.readdir(basePath, { withFileTypes: true }); @@ -451,67 +268,13 @@ class Harness { */ await this.controllers.home.start(); } - - async populateViewModel (viewModel) { - viewModel.DTP_SCRIPT_DEBUG = (process.env.NODE_ENV !== 'production'); - viewModel.dtp = this; - - const pkg = await import(path.join(this.config.root, 'package.json'), { assert: { type: 'json' } }); // jshint ignore:line - viewModel.pkg = pkg.default; // jshint ignore:line - viewModel.dayjs = dayjs; - viewModel.numeral = numeral; - // viewModel.phoneNumberJS = require('libphonenumber-js'); - // viewModel.anchorme = require('anchorme').default; - // viewModel.hljs = hljs; - // viewModel.Color = require('color'); - // viewModel.numberToWords = require('number-to-words'); - viewModel.uuidv4 = (await import('uuid')).v4; - - /* - * Set up the protected markdown renderer that will refuse to process links and images - * for security reasons. - */ - - function safeImageRenderer (href, title, text) { return text; } - function safeLinkRenderer (href, title, text) { return text; } - - function confirmedLinkRenderer (href, title, text) { - return `${text}`; - } - - viewModel.fullMarkedRenderer = new Marked.Renderer(); - viewModel.fullMarkedRenderer.image = safeImageRenderer; - viewModel.fullMarkedRenderer.link = confirmedLinkRenderer; - - viewModel.safeMarkedRenderer = new Marked.Renderer(); - viewModel.safeMarkedRenderer.image = safeImageRenderer; - viewModel.safeMarkedRenderer.link = safeLinkRenderer; - - viewModel.markedConfigChat = { - renderer: this.safeMarkedRenderer, - highlight: function(code, lang) { - const language = hljs.getLanguage(lang) ? lang : 'plaintext'; - return hljs.highlight(code, { language }).value; - }, - langPrefix: 'hljs language-', - pedantic: false, - gfm: true, - breaks: true, - sanitize: false, - smartLists: true, - smartypants: false, - xhtml: false, - }; - Marked.setOptions(viewModel.markedConfigChat); - viewModel.marked = Marked; - } } (async ( ) => { try { - const harness = new Harness(); - await harness.start(); + const app = new SiteWebApp(); + await app.start(); } catch (error) { console.error('failed to start application harness', error); } diff --git a/lib/site-runtime.js b/lib/site-runtime.js new file mode 100644 index 0000000..b599cfe --- /dev/null +++ b/lib/site-runtime.js @@ -0,0 +1,270 @@ +// site-runtime.js +// Copyright (C) 2024 DTP Technologies, LLC +// All Rights Reserved + +'use strict'; + +import 'dotenv/config'; + +import path, { dirname } from 'path'; +import fs from 'fs'; +import { fileURLToPath } from 'url'; +const __dirname = dirname(fileURLToPath(import.meta.url)); // jshint ignore:line + +import { createRequire } from 'module'; +const require = createRequire(import.meta.url); // jshint ignore:line + +import numeral from 'numeral'; +import dayjs from 'dayjs'; +import * as Marked from 'marked'; +import hljs from 'highlight.js'; + +import mongoose from 'mongoose'; +import { Redis } from 'ioredis'; + +import { SiteLog } from './site-lib.js'; +import { SiteTripwire } from './site-tripwire.js'; + +import { Emitter } from '@socket.io/redis-emitter'; + +export class SiteRuntime { + + static get name ( ) { return 'SiteRuntime'; } + static get slug ( ) { return 'runtime'; } + + constructor (RuntimeClass, rootDir) { + this.config = { root: rootDir }; + this.models = [ ]; + this.log = new SiteLog(this, RuntimeClass); + } + + async start ( ) { + await this.loadConfig(); + + this.log.info('loading SiteTripwire (known-malicious request protection)'); + this.tripwire = new SiteTripwire(this); + await this.tripwire.start(); + + await this.connectMongoDB(); + await this.connectRedis(); + + await this.loadModels(); + await this.loadServices(); + } + + async loadConfig ( ) { + this.config.pkg = require(path.join(this.config.root, 'package.json')); + this.config.site = (await import(path.join(this.config.root, 'config', 'site.js'))).default; + this.config.limiter = (await import(path.join(this.config.root, 'config', 'limiter.js'))).default; + this.config.jobQueues = (await import(path.join(this.config.root, 'config', 'job-queues.js'))).default; + } + + async connectMongoDB ( ) { + try { + this.log.info('starting MongoDB'); + + /* + * For some time, strictQuery=true was the Mongoose default. It's being + * changed. The option has to be set manually now. + */ + mongoose.set('strictQuery', true); + + this.log.info('connecting to MongoDB database', { + pid: process.pid, + host: process.env.MONGODB_HOST, + database: process.env.MONGODB_DATABASE, + }); + const mongoConnectUri = `mongodb://${process.env.DTP_MONGODB_HOST}/${process.env.DTP_MONGODB_DATABASE}`; + await mongoose.connect(mongoConnectUri, { + socketTimeoutMS: 0, + dbName: process.env.MONGODB_DATABASE, + }); + this.db = mongoose.connection; + this.log.info('connected to MongoDB'); + } catch (error) { + this.log.error('failed to connect to database', { error }); + throw error; + } + } + + async loadModels ( ) { + const basePath = path.join(this.config.root, 'app', 'models'); + const entries = await fs.promises.readdir(basePath, { withFileTypes: true }); + + this.log.info('loading models', { count: entries.length }); + for (const entry of entries) { + if (!entry.isFile()) { + continue; + } + const filename = path.join(basePath, entry.name); + const model = (await import(filename)).default; + if (this.models[model.modelName]) { + this.log.error('model name collision', { name: model.modelName }); + process.exit(-1); + } + this.models.push(model); + this.log.info('model loaded', { name: model.modelName}); + } + } + + async resetIndexes (target) { + if (target === 'all') { + for (const model of this.models) { + await this.resetIndex(model); + } + return; + } + + const model = this.models.find((model) => model.modelName === target); + if (!model) { + throw new Error(`requested Mongoose model does not exist: ${target}`); + } + + return this.resetIndex(model); + } + + async resetIndex (model) { + return new Promise(async (resolve, reject) => { + this.log.info('dropping model indexes', { model: model.modelName }); + model.collection.dropIndexes((err) => { + if (err) { + return reject(err); + } + this.log.info('creating model indexes', { model: model.modelName }); + model.ensureIndexes((err) => { + if (err) { + return reject(err); + } + return resolve(model); + }); + }); + }); + } + + async connectRedis ( ) { + try { + const options = { + host: process.env.DTP_REDIS_HOST, + port: parseInt(process.env.DTP_REDIS_PORT || '6379', 10), + password: process.env.DTP_REDIS_PASSWORD, + keyPrefix: process.env.DTP_REDIS_KEY_PREFIX, + lazyConnect: false, + }; + this.log.info('connecting to Redis', { + host: options.host, + port: options.port, + prefix: options.keyPrefix || 'dtp', + }); + + this.redis = new Redis(options); + this.redis.setMaxListeners(64); // prevents warnings/errors with Bull Queue + + this.log.info('creating Socket.io Emitter'); + this.emitter = new Emitter(this.redis); + + this.log.info('Redis connected'); + } catch (error) { + this.log.error('failed to connect to Redis', error); + throw new Error('failed to connect to Redis', { cause: error }); + } + } + + async getRedisKeys (pattern) { + return new Promise((resolve, reject) => { + return this.redis.keys(pattern, (err, response) => { + if (err) { + return reject(err); + } + return resolve(response); + }); + }); + } + + async loadServices ( ) { + const basePath = path.join(this.config.root, 'app', 'services'); + const entries = await fs.promises.readdir(basePath, { withFileTypes: true }); + const inits = [ ]; + + this.services = { }; + + for await (const entry of entries) { + if (!entry.isFile()) { + continue; + } + try { + const ServiceClass = (await import(path.join(basePath, entry.name))).default; + this.log.info('loading service', { + script: entry.name, + name: ServiceClass.name, + slug: ServiceClass.slug, + }); + + const service = new ServiceClass(this); + + this.services[ServiceClass.slug] = service; + inits.push(service); + } catch (error) { + this.log.error('failed to load service', { error }); + throw new Error('failed to load service', { cause: error }); + } + } + + for await (const service of inits) { + await service.start(); + } + } + + async populateViewModel (viewModel) { + viewModel.DTP_SCRIPT_DEBUG = (process.env.NODE_ENV !== 'production'); + viewModel.dtp = this; + + const pkg = await import(path.join(this.config.root, 'package.json'), { assert: { type: 'json' } }); // jshint ignore:line + viewModel.pkg = pkg.default; // jshint ignore:line + viewModel.dayjs = dayjs; + viewModel.numeral = numeral; + // viewModel.phoneNumberJS = require('libphonenumber-js'); + // viewModel.anchorme = require('anchorme').default; + // viewModel.hljs = hljs; + // viewModel.Color = require('color'); + // viewModel.numberToWords = require('number-to-words'); + viewModel.uuidv4 = (await import('uuid')).v4; + + /* + * Set up the protected markdown renderer that will refuse to process links and images + * for security reasons. + */ + + function safeImageRenderer (href, title, text) { return text; } + function safeLinkRenderer (href, title, text) { return text; } + + function confirmedLinkRenderer (href, title, text) { + return `${text}`; + } + + viewModel.fullMarkedRenderer = new Marked.Renderer(); + viewModel.fullMarkedRenderer.image = safeImageRenderer; + viewModel.fullMarkedRenderer.link = confirmedLinkRenderer; + + viewModel.safeMarkedRenderer = new Marked.Renderer(); + viewModel.safeMarkedRenderer.image = safeImageRenderer; + viewModel.safeMarkedRenderer.link = safeLinkRenderer; + + viewModel.markedConfigChat = { + renderer: this.safeMarkedRenderer, + highlight: function(code, lang) { + const language = hljs.getLanguage(lang) ? lang : 'plaintext'; + return hljs.highlight(code, { language }).value; + }, + langPrefix: 'hljs language-', + pedantic: false, + gfm: true, + breaks: true, + sanitize: false, + smartLists: true, + smartypants: false, + xhtml: false, + }; + Marked.setOptions(viewModel.markedConfigChat); + viewModel.marked = Marked; + } +} \ No newline at end of file diff --git a/package.json b/package.json index ea696c5..dc69927 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "ioredis": "^5.3.2", "marked": "^12.0.1", "mediasoup": "^3.13.24", + "minio": "^7.1.3", "mongoose": "^8.3.1", "morgan": "^1.10.0", "multer": "^1.4.5-lts.1", diff --git a/start-local b/start-local new file mode 100755 index 0000000..6479dc3 --- /dev/null +++ b/start-local @@ -0,0 +1,11 @@ +#!/bin/bash + +#MINIO_REGION_NAME="us-east-local" +#MINIO_REGION_COMMENT="" +#export MINIO_REGION_NAME MINIO_REGION_COMMENT + +MINIO_ROOT_USER="dtp-chat" +MINIO_ROOT_PASSWORD="dd039ca4-1bab-4a6c-809b-0bbb43c46def" +export MINIO_ROOT_USER MINIO_ROOT_PASSWORD + +minio server ./data/minio --address ":9080" --console-address ":9081" \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index c71ffb0..78497b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1400,6 +1400,11 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== +"@zxing/text-encoding@0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b" + integrity sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA== + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -1587,7 +1592,7 @@ async@^2.6.0: dependencies: lodash "^4.17.14" -async@^3.2.3: +async@^3.2.3, async@^3.2.4: version "3.2.5" resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== @@ -1662,6 +1667,13 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== +block-stream2@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/block-stream2/-/block-stream2-2.1.0.tgz#ac0c5ef4298b3857796e05be8ebed72196fa054b" + integrity sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg== + dependencies: + readable-stream "^3.4.0" + body-parser@1.20.2: version "1.20.2" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" @@ -1702,6 +1714,11 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" +browser-or-node@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/browser-or-node/-/browser-or-node-2.1.1.tgz#738790b3a86a8fc020193fa581273fbe65eaea0f" + integrity sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg== + browser-sync-client@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/browser-sync-client/-/browser-sync-client-3.0.2.tgz#6fbe9a7aada25cf14c824683e089ec9ace91cfe1" @@ -1785,6 +1802,11 @@ bson@^6.4.0, bson@^6.5.0: resolved "https://registry.yarnpkg.com/bson/-/bson-6.6.0.tgz#f225137eb49fe19bee4d87949a0515c05176e2ad" integrity sha512-BVINv2SgcMjL4oYbBuCQTpE3/VKOSxrOA8Cj/wQP7izSzlBGVomdm+TcUd0Pzy0ytLSSDweCKQ6X3f5veM5LQA== +buffer-crc32@^0.2.13: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -2255,6 +2277,11 @@ decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== +decode-uri-component@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== + deepmerge@^4.2.2: version "4.3.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" @@ -2748,6 +2775,13 @@ fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +fast-xml-parser@^4.2.2: + version "4.3.6" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.3.6.tgz#190f9d99097f0c8f2d3a0e681a10404afca052ff" + integrity sha512-M2SovcRxD4+vC493Uc2GZVcZaj66CCJhWurC4viynVSTvrpErCShNcDz1lAho6n9REQKvL/ll4A4/fw6Y9z8nw== + dependencies: + strnum "^1.0.5" + fastest-levenshtein@^1.0.12: version "1.0.16" resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" @@ -2775,6 +2809,11 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +filter-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" + integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ== + finalhandler@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" @@ -3196,6 +3235,19 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== +ipaddr.js@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.1.0.tgz#2119bc447ff8c257753b196fc5f1ce08a4cdf39f" + integrity sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ== + +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + is-array-buffer@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" @@ -3277,6 +3329,13 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-generator-function@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -3369,7 +3428,7 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.13: +is-typed-array@^1.1.13, is-typed-array@^1.1.3: version "1.1.13" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== @@ -3504,6 +3563,11 @@ json-schema@^0.4.0: resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== +json-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-stream/-/json-stream-1.0.0.tgz#1a3854e28d2bbeeab31cc7ddf683d2ddc5652708" + integrity sha512-H/ZGY0nIAg3QcOwE1QN/rK/Fa7gJn7Ii5obwp6zyPO4xiPNwpIMjqy2gwjBEGqzkF/vSWEIBQCBuN19hYiL6Qg== + json5@^2.2.0, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" @@ -3738,7 +3802,7 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.27, mime-types@^2.1.31, mime-types@^2.1.35, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -3789,6 +3853,26 @@ minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +minio@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/minio/-/minio-7.1.3.tgz#86dc95f3671045d6956920db757bb63f25bf20ee" + integrity sha512-xPrLjWkTT5E7H7VnzOjF//xBp9I40jYB4aWhb2xTFopXXfw+Wo82DDWngdUju7Doy3Wk7R8C4LAgwhLHHnf0wA== + dependencies: + async "^3.2.4" + block-stream2 "^2.1.0" + browser-or-node "^2.1.1" + buffer-crc32 "^0.2.13" + fast-xml-parser "^4.2.2" + ipaddr.js "^2.0.1" + json-stream "^1.0.0" + lodash "^4.17.21" + mime-types "^2.1.35" + query-string "^7.1.3" + through2 "^4.0.2" + web-encoding "^1.1.5" + xml "^1.0.1" + xml2js "^0.5.0" + minipass@^3.0.0: version "3.3.6" resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" @@ -4445,6 +4529,16 @@ qs@6.11.0: dependencies: side-channel "^1.0.4" +query-string@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328" + integrity sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg== + dependencies: + decode-uri-component "^0.2.2" + filter-obj "^1.1.0" + split-on-first "^1.0.0" + strict-uri-encode "^2.0.0" + randexp@^0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.5.3.tgz#f31c2de3148b30bdeb84b7c3f59b0ebb9fec3738" @@ -4495,6 +4589,15 @@ readable-stream@1.1: isarray "0.0.1" string_decoder "~0.10.x" +readable-stream@3, readable-stream@^3.4.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readable-stream@^2.0.1, readable-stream@^2.2.2, readable-stream@^2.3.5: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" @@ -4693,7 +4796,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1, safe-buffer@^5.1.0: +safe-buffer@5.2.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -4712,7 +4815,7 @@ safe-regex-test@^1.0.3: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@^1.2.4: +sax@>=0.6.0, sax@^1.2.4: version "1.3.0" resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0" integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== @@ -5014,6 +5117,11 @@ sparse-bitfield@^3.0.3: dependencies: memory-pager "^1.0.2" +split-on-first@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" + integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== + standard-as-callback@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" @@ -5059,6 +5167,11 @@ streamsearch@^1.1.0: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== +strict-uri-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" + integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== + string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: name string-width-cjs version "4.2.3" @@ -5115,6 +5228,13 @@ string.prototype.trimstart@^1.0.7: define-properties "^1.2.1" es-object-atoms "^1.0.0" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" @@ -5159,6 +5279,11 @@ striptags@^3.2.0: resolved "https://registry.yarnpkg.com/striptags/-/striptags-3.2.0.tgz#cc74a137db2de8b0b9a370006334161f7dd67052" integrity sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw== +strnum@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" + integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== + style-loader@^3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.4.tgz#f30f786c36db03a45cbd55b6a70d930c479090e7" @@ -5260,6 +5385,13 @@ thirty-two@^1.0.2: resolved "https://registry.yarnpkg.com/thirty-two/-/thirty-two-1.0.2.tgz#4ca2fffc02a51290d2744b9e3f557693ca6b627a" integrity sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA== +through2@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" + integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== + dependencies: + readable-stream "3" + through@^2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -5499,11 +5631,22 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -util-deprecate@^1.0.2, util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +util@^0.12.3: + version "0.12.5" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" + integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + which-typed-array "^1.1.2" + utils-merge@1.0.1, utils-merge@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -5549,6 +5692,15 @@ watchpack@^2.4.1: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" +web-encoding@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/web-encoding/-/web-encoding-1.1.5.tgz#fc810cf7667364a6335c939913f5051d3e0c4864" + integrity sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA== + dependencies: + util "^0.12.3" + optionalDependencies: + "@zxing/text-encoding" "0.9.0" + web-streams-polyfill@^3.0.3: version "3.3.3" resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b" @@ -5694,7 +5846,7 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== -which-typed-array@^1.1.14, which-typed-array@^1.1.15: +which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.2: version "1.1.15" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== @@ -5925,6 +6077,24 @@ ws@~8.11.0: resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143" integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== +xml2js@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.5.0.tgz#d9440631fbb2ed800203fad106f2724f62c493b7" + integrity sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + +xml@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== + +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + xmlhttprequest-ssl@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67"