diff --git a/.eslintrc.js b/.eslintrc.cjs similarity index 99% rename from .eslintrc.js rename to .eslintrc.cjs index 1e35f46..b735070 100644 --- a/.eslintrc.js +++ b/.eslintrc.cjs @@ -1,7 +1,6 @@ module.exports = { env: { - commonjs: true, - es6: true, + es2021: true, node: true, browser: true, mocha: true, @@ -17,7 +16,6 @@ module.exports = { fetch: true, }, parserOptions: { - ecmaVersion: 2018, sourceType: 'module', }, rules: { diff --git a/conf/config.json b/conf/config.json index 70ecabf..6df9d31 100755 --- a/conf/config.json +++ b/conf/config.json @@ -1 +1 @@ -{"interval":"60","port":9998,"scrapingAnt":{"apiKey":"","proxy":"datacenter"},"workingHours":{"from":"","to":""}} +{"interval":"60","port":9998,"scrapingAnt":{"apiKey":"","proxy":"datacenter"},"workingHours":{"from":"","to":""}} \ No newline at end of file diff --git a/index.js b/index.js index 5cdac03..c1e38d1 100755 --- a/index.js +++ b/index.js @@ -1,41 +1,31 @@ -const fs = require('fs'); - +import fs from 'fs'; +import { config } from './lib/utils.js'; +import * as similarityCache from './lib/services/similarity-check/similarityCache.js'; +import { setLastJobExecution } from './lib/services/storage/listingsStorage.js'; +import * as jobStorage from './lib/services/storage/jobStorage.js'; +import FredyRuntime from './lib/FredyRuntime.js'; +import { duringWorkingHoursOrNotSet } from './lib/utils.js'; +import './lib/api/api.js'; //if db folder does not exist, ensure to create it before loading anything else if (!fs.existsSync('./db')) { fs.mkdirSync('./db'); } - const path = './lib/provider'; const provider = fs.readdirSync(path).filter((file) => file.endsWith('.js')); -const config = require('./conf/config.json'); - -const similarityCache = require('./lib/services/similarity-check/similarityCache'); -const { setLastJobExecution } = require('./lib/services/storage/listingsStorage'); -const jobStorage = require('./lib/services/storage/jobStorage'); -const FredyRuntime = require('./lib/FredyRuntime'); - -const { duringWorkingHoursOrNotSet } = require('./lib/utils'); - -//starting the api service -require('./lib/api/api'); - //assuming interval is always in minutes - const INTERVAL = config.interval * 60 * 1000; - /* eslint-disable no-console */ console.log(`Started Fredy successfully. Ui can be accessed via http://localhost:${config.port}`); /* eslint-enable no-console */ +const fetchedProvider = await Promise.all( + provider.filter((provider) => provider.endsWith('.js')).map(async (pro) => import(`${path}/${pro}`)) +); + setInterval( (function exec() { const isDuringWorkingHoursOrNotSet = duringWorkingHoursOrNotSet(config, Date.now()); - if (isDuringWorkingHoursOrNotSet) { config.lastRun = Date.now(); - const fetchedProvider = provider - .filter((provider) => provider.endsWith('.js')) - .map((pro) => require(`${path}/${pro}`)); - jobStorage .getJobs() .filter((job) => job.enabled) diff --git a/lib/FredyRuntime.js b/lib/FredyRuntime.js index aff2fe8..1c82f3a 100755 --- a/lib/FredyRuntime.js +++ b/lib/FredyRuntime.js @@ -1,11 +1,9 @@ -const { NoNewListingsWarning } = require('./errors'); -const { setKnownListings, getKnownListings } = require('./services/storage/listingsStorage'); - -const notify = require('./notification/notify'); -const xray = require('./services/scraper'); -const scrapingAnt = require('./services/scrapingAnt'); -const urlModifier = require('./services/queryStringMutator'); - +import { NoNewListingsWarning } from './errors.js'; +import { setKnownListings, getKnownListings } from './services/storage/listingsStorage.js'; +import * as notify from './notification/notify.js'; +import xray from './services/scraper.js'; +import * as scrapingAnt from './services/scrapingAnt.js'; +import urlModifier from './services/queryStringMutator.js'; class FredyRuntime { /** * @@ -22,7 +20,6 @@ class FredyRuntime { this._jobKey = jobKey; this._similarityCache = similarityCache; } - execute() { return ( //modify the url to make sure search order is correctly set @@ -45,7 +42,6 @@ class FredyRuntime { .catch(this._handleError.bind(this)) ); } - _getListings(url) { return new Promise((resolve, reject) => { const id = this._providerId; @@ -87,25 +83,19 @@ class FredyRuntime { } }); } - _normalize(listings) { return listings.map(this._providerConfig.normalize); } - _filter(listings) { return listings.filter(this._providerConfig.filter); } - _findNew(listings) { const newListings = listings.filter((o) => getKnownListings(this._jobKey, this._providerId)[o.id] == null); - if (newListings.length === 0) { throw new NoNewListingsWarning(); } - return newListings; } - _notify(newListings) { if (newListings.length === 0) { throw new NoNewListingsWarning(); @@ -113,7 +103,6 @@ class FredyRuntime { const sendNotifications = notify.send(this._providerId, newListings, this._notificationConfig, this._jobKey); return Promise.all(sendNotifications).then(() => newListings); } - _save(newListings) { const currentListings = getKnownListings(this._jobKey, this._providerId) || {}; newListings.forEach((listing) => { @@ -122,7 +111,6 @@ class FredyRuntime { setKnownListings(this._jobKey, this._providerId, currentListings); return newListings; } - _filterBySimilarListings(listings) { const filteredList = listings.filter((listing) => { const similar = this._similarityCache.hasSimilarEntries(this._jobKey, listing.title); @@ -136,10 +124,8 @@ class FredyRuntime { filteredList.forEach((filter) => this._similarityCache.addCacheEntry(this._jobKey, filter.title)); return filteredList; } - _handleError(err) { if (err.name !== 'NoNewListingsWarning') console.error(err); } } - -module.exports = FredyRuntime; +export default FredyRuntime; diff --git a/lib/api/api.js b/lib/api/api.js index 14c08e0..5e67439 100644 --- a/lib/api/api.js +++ b/lib/api/api.js @@ -1,44 +1,36 @@ -const { notificationAdapterRouter } = require('./routes/notificationAdapterRouter'); -const { authInterceptor, cookieSession, adminInterceptor } = require('./security'); -const { generalSettingsRouter } = require('./routes/generalSettingsRoute'); -const { analyticsRouter } = require('./routes/analyticsRouter'); -const { providerRouter } = require('./routes/providerRouter'); -const { loginRouter } = require('./routes/loginRoute'); -const config = require('../../conf/config.json'); -const { userRouter } = require('./routes/userRoute'); -const { jobRouter } = require('./routes/jobRouter'); -const bodyParser = require('body-parser'); -const service = require('restana')(); -const files = require('serve-static'); -const path = require('path'); - -const staticService = files(path.join(__dirname, '../../ui/public')); - +import { notificationAdapterRouter } from './routes/notificationAdapterRouter.js'; +import { authInterceptor, cookieSession, adminInterceptor } from './security.js'; +import { generalSettingsRouter } from './routes/generalSettingsRoute.js'; +import { analyticsRouter } from './routes/analyticsRouter.js'; +import { providerRouter } from './routes/providerRouter.js'; +import { loginRouter } from './routes/loginRoute.js'; +import { config } from '../utils.js'; +import { userRouter } from './routes/userRoute.js'; +import { jobRouter } from './routes/jobRouter.js'; +import bodyParser from 'body-parser'; +import restana from 'restana'; +import files from 'serve-static'; +import path from 'path'; +import { getDirName } from '../utils.js'; +const service = restana(); +const staticService = files(path.join(getDirName(), '../../ui/public')); const PORT = config.port || 9998; service.use(bodyParser.json()); - service.use(cookieSession()); - service.use(staticService); - service.use('/api/admin', authInterceptor()); service.use('/api/jobs', authInterceptor()); - // /admin can only be accessed when user is having admin permissions service.use('/api/admin', adminInterceptor()); - service.use('/api/jobs/notificationAdapter', notificationAdapterRouter); service.use('/api/admin/generalSettings', generalSettingsRouter); service.use('/api/jobs/provider', providerRouter); service.use('/api/jobs/insights', analyticsRouter); service.use('/api/admin/users', userRouter); service.use('/api/jobs', jobRouter); - service.use('/api/login', loginRouter); - /* eslint-disable no-console */ service.start(PORT).then(() => { console.info(`Started API service on port ${PORT}`); }); -/* eslint-enable no-console */ diff --git a/lib/api/routes/analyticsRouter.js b/lib/api/routes/analyticsRouter.js index 215c159..6d95b7a 100644 --- a/lib/api/routes/analyticsRouter.js +++ b/lib/api/routes/analyticsRouter.js @@ -1,12 +1,10 @@ -const service = require('restana')(); +import restana from 'restana'; +import * as listingStorage from '../../services/storage/listingsStorage.js'; +const service = restana(); const analyticsRouter = service.newRouter(); -const listingStorage = require('../../services/storage/listingsStorage'); - analyticsRouter.get('/:jobId', async (req, res) => { const { jobId } = req.params; - res.body = listingStorage.getListingProviderDataForAnalytics(jobId) || {}; res.send(); }); - -exports.analyticsRouter = analyticsRouter; +export { analyticsRouter }; diff --git a/lib/api/routes/generalSettingsRoute.js b/lib/api/routes/generalSettingsRoute.js index 97607b3..92b3379 100644 --- a/lib/api/routes/generalSettingsRoute.js +++ b/lib/api/routes/generalSettingsRoute.js @@ -1,18 +1,16 @@ -const service = require('restana')(); +import restana from 'restana'; +import { config, getDirName } from '../../utils.js'; +import fs from 'fs'; +const service = restana(); const generalSettingsRouter = service.newRouter(); -const config = require('../../../conf/config.json'); -const fs = require('fs'); - generalSettingsRouter.get('/', async (req, res) => { res.body = Object.assign({}, config); res.send(); }); - generalSettingsRouter.post('/', async (req, res) => { const settings = req.body; - try { - fs.writeFileSync(`${__dirname}/../../../conf/config.json`, JSON.stringify(settings)); + fs.writeFileSync(`${getDirName()}/../conf/config.json`, JSON.stringify(settings)); } catch (err) { console.error(err); res.send(new Error('Error while trying to write settings.')); @@ -20,5 +18,4 @@ generalSettingsRouter.post('/', async (req, res) => { } res.send(); }); - -exports.generalSettingsRouter = generalSettingsRouter; +export { generalSettingsRouter }; diff --git a/lib/api/routes/jobRouter.js b/lib/api/routes/jobRouter.js index 5ad3762..c4690e3 100644 --- a/lib/api/routes/jobRouter.js +++ b/lib/api/routes/jobRouter.js @@ -1,12 +1,12 @@ -const service = require('restana')(); +import restana from 'restana'; +import fetch from 'node-fetch'; +import * as jobStorage from '../../services/storage/jobStorage.js'; +import * as userStorage from '../../services/storage/userStorage.js'; +import * as immoscoutProvider from '../../provider/immoscout.js'; +import { config } from '../../utils.js'; +import { isAdmin } from '../security.js'; +const service = restana(); const jobRouter = service.newRouter(); -const fetch = require('node-fetch'); -const jobStorage = require('../../services/storage/jobStorage'); -const userStorage = require('../../services/storage/userStorage'); -const immoscoutProvider = require('../../provider/immoscout'); -const config = require('../../../conf/config.json'); -const { isAdmin } = require('../security'); - function doesJobBelongsToUser(job, req) { const userId = req.session.currentUser; if (userId == null) { @@ -16,22 +16,16 @@ function doesJobBelongsToUser(job, req) { if (user == null) { return false; } - return user.isAdmin || job.userId === job.userId; } - jobRouter.get('/', async (req, res) => { const isUserAdmin = isAdmin(req); - //show only the jobs which belongs to the user (or all of the user is an admin) res.body = jobStorage.getJobs().filter((job) => isUserAdmin || job.userId === req.session.currentUser); - res.send(); }); - jobRouter.get('/processingTimes', async (req, res) => { let scrapingAntData = null; - if (config.scrapingAnt.apiKey != null && config.scrapingAnt.apiKey.length > 0) { try { const response = await fetch(`https://api.scrapingant.com/v1/usage?x-api-key=${config.scrapingAnt.apiKey}`); @@ -40,16 +34,13 @@ jobRouter.get('/processingTimes', async (req, res) => { console.error('Could not query plan data from scraping ant.', Exception); } } - res.body = { interval: config.interval, lastRun: config.lastRun || null, scrapingAntData, }; - res.send(); }); - jobRouter.post('/', async (req, res) => { const { provider, notificationAdapter, name, blacklist = [], jobId, enabled } = req.body; if ( @@ -77,7 +68,6 @@ jobRouter.post('/', async (req, res) => { } res.send(); }); - jobRouter.delete('', async (req, res) => { const { jobId } = req.body; try { @@ -93,7 +83,6 @@ jobRouter.delete('', async (req, res) => { } res.send(); }); - jobRouter.put('/:jobId/status', async (req, res) => { const { status } = req.body; const { jobId } = req.params; @@ -113,5 +102,4 @@ jobRouter.put('/:jobId/status', async (req, res) => { } res.send(); }); - -exports.jobRouter = jobRouter; +export { jobRouter }; diff --git a/lib/api/routes/loginRoute.js b/lib/api/routes/loginRoute.js index ff7e0b7..c41240b 100644 --- a/lib/api/routes/loginRoute.js +++ b/lib/api/routes/loginRoute.js @@ -1,8 +1,8 @@ -const service = require('restana')(); +import restana from 'restana'; +import * as userStorage from '../../services/storage/userStorage.js'; +import * as hasher from '../../services/security/hash.js'; +const service = restana(); const loginRouter = service.newRouter(); -const userStorage = require('../../services/storage/userStorage'); -const hasher = require('../../services/security/hash'); - loginRouter.get('/user', async (req, res) => { const currentUserId = req.session.currentUser; const currentUser = currentUserId == null ? null : userStorage.getUser(currentUserId); @@ -16,17 +16,13 @@ loginRouter.get('/user', async (req, res) => { } res.send(); }); - loginRouter.post('/', async (req, res) => { const { username, password } = req.body; - const user = userStorage.getUsers(true).find((user) => user.username === username); - if (user == null) { res.send(401); return; } - if (user.password === hasher.hash(password)) { req.session.currentUser = user.id; userStorage.setLastLoginToNow({ userId: user.id }); @@ -35,13 +31,10 @@ loginRouter.post('/', async (req, res) => { } else { console.error(`User ${username} tried to login, but password was wrong.`); } - res.send(401); }); - loginRouter.post('/logout', async (req, res) => { req.session = null; res.send(200); }); - -exports.loginRouter = loginRouter; +export { loginRouter }; diff --git a/lib/api/routes/notificationAdapterRouter.js b/lib/api/routes/notificationAdapterRouter.js index a8cfa15..483fa14 100644 --- a/lib/api/routes/notificationAdapterRouter.js +++ b/lib/api/routes/notificationAdapterRouter.js @@ -1,13 +1,13 @@ -const fs = require('fs'); -const service = require('restana')(); +import fs from 'fs'; +import restana from 'restana'; +const service = restana(); const notificationAdapterRouter = service.newRouter(); - const notificationAdapterList = fs.readdirSync('./lib//notification/adapter').filter((file) => file.endsWith('.js')); - -const notificationAdapter = notificationAdapterList.map((pro) => { - return require(`../../notification/adapter/${pro}`); -}); - +const notificationAdapter = await Promise.all( + notificationAdapterList.map(async (pro) => { + return await import(`../../notification/adapter/${pro}`); + }) +); notificationAdapterRouter.post('/try', async (req, res) => { const { id, fields } = req.body; const adapter = notificationAdapter.find((adapter) => adapter.config.id === id); @@ -24,7 +24,6 @@ notificationAdapterRouter.post('/try', async (req, res) => { enabled: true, id, }); - try { await adapter.send({ serviceName: 'TestCall', @@ -40,16 +39,13 @@ notificationAdapterRouter.post('/try', async (req, res) => { notificationConfig, jobKey: 'TestJob', }); - res.send(); } catch (Exception) { res.send(new Error(Exception)); } }); - notificationAdapterRouter.get('/', async (req, res) => { res.body = notificationAdapter.map((adapter) => adapter.config); res.send(); }); - -exports.notificationAdapterRouter = notificationAdapterRouter; +export { notificationAdapterRouter }; diff --git a/lib/api/routes/providerRouter.js b/lib/api/routes/providerRouter.js index 58ddbb7..2718baa 100644 --- a/lib/api/routes/providerRouter.js +++ b/lib/api/routes/providerRouter.js @@ -1,16 +1,15 @@ -const fs = require('fs'); -const service = require('restana')(); +import fs from 'fs'; +import restana from 'restana'; +const service = restana(); const providerRouter = service.newRouter(); - const providerList = fs.readdirSync('./lib/provider').filter((file) => file.endsWith('.js')); - -const provider = providerList.map((pro) => { - return require(`../../provider/${pro}`).metaInformation; -}); - +const provider = await Promise.all( + providerList.map(async (pro) => { + return await import(`../../provider/${pro}`); + }) +); providerRouter.get('/', async (req, res) => { - res.body = provider; + res.body = provider.map((p) => p.metaInformation); res.send(); }); - -exports.providerRouter = providerRouter; +export { providerRouter }; diff --git a/lib/api/routes/userRoute.js b/lib/api/routes/userRoute.js index 33de8ce..f57035b 100644 --- a/lib/api/routes/userRoute.js +++ b/lib/api/routes/userRoute.js @@ -1,33 +1,27 @@ -const service = require('restana')(); +import restana from 'restana'; +import * as userStorage from '../../services/storage/userStorage.js'; +import * as jobStorage from '../../services/storage/jobStorage.js'; +const service = restana(); const userRouter = service.newRouter(); -const userStorage = require('../../services/storage/userStorage'); -const jobStorage = require('../../services/storage/jobStorage'); - function checkIfAnyAdminAfterRemovingUser(userIdToBeRemoved, allUser) { return allUser.filter((user) => user.id !== userIdToBeRemoved && user.isAdmin).length > 0; } - function checkIfUserToBeRemovedIsLoggedIn(userIdToBeRemoved, req) { return req.session.currentUser === userIdToBeRemoved; } - const nullOrEmpty = (str) => str == null || str.length === 0; - userRouter.get('/', async (req, res) => { res.body = userStorage.getUsers(false); res.send(); }); - userRouter.get('/:userId', async (req, res) => { const { userId } = req.params; res.body = userStorage.getUser(userId); res.send(); }); - userRouter.delete('/', async (req, res) => { const { userId } = req.body; const allUser = userStorage.getUsers(false); - if (!checkIfAnyAdminAfterRemovingUser(userId, allUser)) { res.send(new Error('You are trying to remove the last admin user. This is prohibited.')); return; @@ -36,14 +30,11 @@ userRouter.delete('/', async (req, res) => { res.send(new Error('You are trying to remove yourself. This is prohibited.')); return; } - //TODO: Remove also analytics jobStorage.removeJobsByUserId(userId); userStorage.removeUser(userId); - res.send(); }); - userRouter.post('/', async (req, res) => { const { username, password, password2, isAdmin, userId } = req.body; if (password !== password2) { @@ -55,22 +46,18 @@ userRouter.post('/', async (req, res) => { return; } const allUser = userStorage.getUsers(false); - if (!isAdmin && !checkIfAnyAdminAfterRemovingUser(userId, allUser)) { res.send( new Error('You cannot change the admin flag for this user as otherwise, there is no other user in the system') ); return; } - userStorage.upsertUser({ userId, username, password, isAdmin, }); - res.send(); }); - -exports.userRouter = userRouter; +export { userRouter }; diff --git a/lib/api/security.js b/lib/api/security.js index 0d463dc..65a5e92 100644 --- a/lib/api/security.js +++ b/lib/api/security.js @@ -1,15 +1,12 @@ -const userStorage = require('../services/storage/userStorage'); -const cookieSession = require('cookie-session'); -const { nanoid } = require('nanoid'); - +import * as userStorage from '../services/storage/userStorage.js'; +import cookieSession from 'cookie-session'; +import { nanoid } from 'nanoid'; const unauthorized = (res) => { return res.send(401); }; - const isUnauthorized = (req) => { return req.session.currentUser == null; }; - const isAdmin = (req) => { if (!isUnauthorized(req)) { const user = userStorage.getUser(req.session.currentUser); @@ -17,7 +14,6 @@ const isAdmin = (req) => { } return false; }; - const authInterceptor = () => { return (req, res, next) => { if (isUnauthorized(req)) { @@ -27,7 +23,6 @@ const authInterceptor = () => { } }; }; - const adminInterceptor = () => { return (req, res, next) => { if (!isAdmin(req)) { @@ -37,8 +32,7 @@ const adminInterceptor = () => { } }; }; - -exports.cookieSession = (userId) => { +const cookieSession$0 = (userId) => { return cookieSession({ name: 'fredy-admin-session', keys: ['fredy', 'super', 'fancy', 'key', nanoid()], @@ -46,8 +40,8 @@ exports.cookieSession = (userId) => { maxAge: 8 * 60 * 60 * 1000, // 8 hours }); }; - -exports.adminInterceptor = adminInterceptor; -exports.authInterceptor = authInterceptor; -exports.isUnauthorized = isUnauthorized; -exports.isAdmin = isAdmin; +export { cookieSession$0 as cookieSession }; +export { adminInterceptor }; +export { authInterceptor }; +export { isUnauthorized }; +export { isAdmin }; diff --git a/lib/errors.js b/lib/errors.js index 4aa13a6..04afe8c 100755 --- a/lib/errors.js +++ b/lib/errors.js @@ -9,7 +9,8 @@ class ExtendableError extends Error { } } } - class NoNewListingsWarning extends ExtendableError {} - -module.exports = { NoNewListingsWarning }; +export { NoNewListingsWarning }; +export default { + NoNewListingsWarning, +}; diff --git a/lib/notification/adapter/console.js b/lib/notification/adapter/console.js index 4759b29..4f2a493 100755 --- a/lib/notification/adapter/console.js +++ b/lib/notification/adapter/console.js @@ -1,19 +1,12 @@ -const { markdown2Html } = require('../../services/markdown'); +import { markdown2Html } from '../../services/markdown.js'; -/** - * simply prints out the found data to the console - * @param serviceName e.g immowelt - * @param newListings an array with newly found listings - * @param jobKey name of the current job that is being executed - */ -exports.send = ({ serviceName, newListings, jobKey }) => { +export const send = ({ serviceName, newListings, jobKey }) => { /* eslint-disable no-console */ return [Promise.resolve(console.info(`Found entry from service ${serviceName}, Job: ${jobKey}:`, newListings))]; /* eslint-enable no-console */ }; - -exports.config = { - id: __filename.slice(__dirname.length + 1, -3), +export const config = { + id: 'console', name: 'Console', description: 'This adapter sends new listings to the console. It is mostly useful for debugging.', config: {}, diff --git a/lib/notification/adapter/mailJet.js b/lib/notification/adapter/mailJet.js index 72f9f68..69be4f6 100755 --- a/lib/notification/adapter/mailJet.js +++ b/lib/notification/adapter/mailJet.js @@ -1,33 +1,22 @@ -const mailjet = require('node-mailjet'); - -const path = require('path'); -const fs = require('fs'); -const template = fs.readFileSync(path.resolve(__dirname, '../', 'emailTemplate/template.hbs'), 'utf8'); - -const Handlebars = require('handlebars'); +import mailjet from 'node-mailjet'; +import path from 'path'; +import fs from 'fs'; +import Handlebars from 'handlebars'; +import { markdown2Html } from '../../services/markdown.js'; +import { getDirName } from '../../utils.js'; +const __dirname = getDirName(); +const template = fs.readFileSync(path.resolve(__dirname + '/notification/emailTemplate/template.hbs'), 'utf8'); const emailTemplate = Handlebars.compile(template); -const { markdown2Html } = require('../../services/markdown'); - -/** - * sends a new listing using MailJet - * @param serviceName e.g immowelt - * @param newListings an array with newly found listings - * @param notificationConfig config of this notification adapter - * * @param jobKey name of the current job that is being executed - * @returns {Promise | void} - */ -exports.send = ({ serviceName, newListings, notificationConfig, jobKey }) => { +export const send = ({ serviceName, newListings, notificationConfig, jobKey }) => { const { apiPublicKey, apiPrivateKey, receiver, from } = notificationConfig.find( (adapter) => adapter.id === 'mailJet' ).fields; - const to = receiver .trim() .split(',') .map((r) => ({ Email: r.trim(), })); - return mailjet .connect(apiPublicKey, apiPrivateKey) .post('send', { version: 'v3.1' }) @@ -49,9 +38,8 @@ exports.send = ({ serviceName, newListings, notificationConfig, jobKey }) => { ], }); }; - -exports.config = { - id: __filename.slice(__dirname.length + 1, -3), +export const config = { + id: 'mailjet', name: 'MailJet', description: 'MailJet is being used to send new listings via mail.', readme: markdown2Html('lib/notification/adapter/mailJet.md'), diff --git a/lib/notification/adapter/mattermost.js b/lib/notification/adapter/mattermost.js index a1cb217..f5246c9 100644 --- a/lib/notification/adapter/mattermost.js +++ b/lib/notification/adapter/mattermost.js @@ -1,26 +1,15 @@ -const { markdown2Html } = require('../../services/markdown'); -const { getJob } = require('../../services/storage/jobStorage'); -const fetch = require('node-fetch'); - -/** - * sends new listings to mattermost - * @param serviceName e.g immowelt - * @param newListings an array with newly found listings - * @param notificationConfig config of this notification adapter - * @param jobKey name of the current job that is being executed - * @returns {Promise | void} - */ -exports.send = ({ serviceName, newListings, notificationConfig, jobKey }) => { +import { markdown2Html } from '../../services/markdown.js'; +import { getJob } from '../../services/storage/jobStorage.js'; +import fetch from 'node-fetch'; +export const send = ({ serviceName, newListings, notificationConfig, jobKey }) => { const { webhook, channel } = notificationConfig.find((adapter) => adapter.id === 'mattermost').fields; const job = getJob(jobKey); const jobName = job == null ? jobKey : job.name; - let message = `### *${jobName}* (${serviceName}) found **${newListings.length}** new listings:\n\n`; message += `| Title | Address | Size | Price |\n|:----|:----|:----|:----|\n`; message += newListings.map( (o) => `| [${o.title}](${o.link}) | ` + [o.address, o.size.replace(/2m/g, '$m^2$'), o.price].join(' | ') + ' |\n' ); - return fetch(webhook, { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -30,14 +19,8 @@ exports.send = ({ serviceName, newListings, notificationConfig, jobKey }) => { }, }); }; - -/** - * exported config is being used in the frontend to generate the fields - * incoming values will be the keys (and values) of the fields - * - */ -exports.config = { - id: __filename.slice(__dirname.length + 1, -3), +export const config = { + id: 'mattermost', name: 'Mattermost', readme: markdown2Html('lib/notification/adapter/mattermost.md'), description: 'Fredy will send new listings to your mattermost team chat.', diff --git a/lib/notification/adapter/sendGrid.js b/lib/notification/adapter/sendGrid.js index ace33c0..875adac 100755 --- a/lib/notification/adapter/sendGrid.js +++ b/lib/notification/adapter/sendGrid.js @@ -1,15 +1,6 @@ -const sgMail = require('@sendgrid/mail'); -const { markdown2Html } = require('../../services/markdown'); - -/** - * sends a new listing using SendGrid - * @param serviceName e.g immowelt - * @param newListings an array with newly found listings - * @param notificationConfig config of this notification adapter - * @param jobKey name of the current job that is being executed - * @returns {Promise | void} - */ -exports.send = ({ serviceName, newListings, notificationConfig, jobKey }) => { +import sgMail from '@sendgrid/mail'; +import { markdown2Html } from '../../services/markdown.js'; +export const send = ({ serviceName, newListings, notificationConfig, jobKey }) => { const { apiKey, receiver, from, templateId } = notificationConfig.find((adapter) => adapter.id === 'sendGrid').fields; sgMail.setApiKey(apiKey); const msg = { @@ -28,9 +19,8 @@ exports.send = ({ serviceName, newListings, notificationConfig, jobKey }) => { }; return sgMail.send(msg); }; - -exports.config = { - id: __filename.slice(__dirname.length + 1, -3), +export const config = { + id: 'sendgrid', name: 'SendGrid', description: 'SendGrid is being used to send new listings via mail.', readme: markdown2Html('lib/notification/adapter/sendGrid.md'), diff --git a/lib/notification/adapter/slack.js b/lib/notification/adapter/slack.js index 5f8d6ef..96482c3 100755 --- a/lib/notification/adapter/slack.js +++ b/lib/notification/adapter/slack.js @@ -1,16 +1,7 @@ -const Slack = require('slack'); +import Slack from 'slack'; +import { markdown2Html } from '../../services/markdown.js'; const msg = Slack.chat.postMessage; -const { markdown2Html } = require('../../services/markdown'); - -/** - * sends a new listing to slack - * @param serviceName e.g immowelt - * @param newListings an array with newly found listings - * @param notificationConfig config of this notification adapter - * * @param jobKey name of the current job that is being executed - * @returns {Promise | void} - */ -exports.send = ({ serviceName, newListings, notificationConfig, jobKey }) => { +export const send = ({ serviceName, newListings, notificationConfig, jobKey }) => { const { token, channel } = notificationConfig.find((adapter) => adapter.id === 'slack').fields; return newListings.map((payload) => msg({ @@ -47,9 +38,8 @@ exports.send = ({ serviceName, newListings, notificationConfig, jobKey }) => { }) ); }; - -exports.config = { - id: __filename.slice(__dirname.length + 1, -3), +export const config = { + id: 'slack', name: 'Slack', readme: markdown2Html('lib/notification/adapter/slack.md'), description: 'Fredy will send new listings to the slack channel of your choice..', diff --git a/lib/notification/adapter/sqlite.js b/lib/notification/adapter/sqlite.js index cf699c8..e48a6c2 100644 --- a/lib/notification/adapter/sqlite.js +++ b/lib/notification/adapter/sqlite.js @@ -1,13 +1,6 @@ -const { markdown2Html } = require('../../services/markdown'); -const Database = require('better-sqlite3'); - -/** - * Stores data in a sqlite db in order to use the search results for later analytics - * @param serviceName e.g immowelt - * @param newListings an array with newly found listings - * @param jobKey name of the current job that is being executed - */ -exports.send = ({ serviceName, newListings, jobKey }) => { +import { markdown2Html } from '../../services/markdown.js'; +import Database from 'better-sqlite3'; +export const send = ({ serviceName, newListings, jobKey }) => { const db = new Database('db/listings.db'); const fields = ['serviceName', 'jobKey', 'id', 'size', 'rooms', 'price', 'address', 'title', 'link', 'description']; db.prepare(`CREATE TABLE IF NOT EXISTS listing (${fields.join(' TEXT, ')} TEXT);`).run(); @@ -23,9 +16,8 @@ exports.send = ({ serviceName, newListings, jobKey }) => { }); return Promise.resolve(); }; - -exports.config = { - id: __filename.slice(__dirname.length + 1, -3), +export const config = { + id: 'sqlite', name: 'Sqlite', description: 'This adapter stores listings in a local sqlite3 database.', config: {}, diff --git a/lib/notification/adapter/telegram.js b/lib/notification/adapter/telegram.js index b233a4d..48cb4ef 100644 --- a/lib/notification/adapter/telegram.js +++ b/lib/notification/adapter/telegram.js @@ -1,7 +1,6 @@ -const { markdown2Html } = require('../../services/markdown'); -const { getJob } = require('../../services/storage/jobStorage'); -const fetch = require('node-fetch'); - +import { markdown2Html } from '../../services/markdown.js'; +import { getJob } from '../../services/storage/jobStorage.js'; +import fetch from 'node-fetch'; const MAX_ENTITIES_PER_CHUNK = 8; const RATE_LIMIT_INTERVAL = 1010; /** @@ -16,32 +15,23 @@ const arrayChunks = (inputArray, perChunk) => all[ch] = [].concat(all[ch] || [], one); return all; }, []); - -/** - * sends new listings to telegram - * @param serviceName e.g immowelt - * @param newListings an array with newly found listings - * @param notificationConfig config of this notification adapter - * @param jobKey name of the current job that is being executed - * @returns {Promise | void} - */ -exports.send = ({ serviceName, newListings, notificationConfig, jobKey }) => { +function shorten(str, len = 30) { + return str.length > len ? str.substring(0, len) + '...' : str; +} +export const send = ({ serviceName, newListings, notificationConfig, jobKey }) => { const { token, chatId } = notificationConfig.find((adapter) => adapter.id === 'telegram').fields; const job = getJob(jobKey); const jobName = job == null ? jobKey : job.name; - //we have to split messages into chunk, because otherwise messages are going to become too big and will fail const chunks = arrayChunks(newListings, MAX_ENTITIES_PER_CHUNK); - const promises = chunks.map((chunk) => { let message = `${jobName} (${serviceName}) found ${newListings.length} new listings:\n\n`; message += chunk.map( (o) => - `${shorten(o.title.replace(/\*/g, ''), 45).trim()}\n` + + `${shorten(o.title.replace(/\*/g, ''), 45).trim()}\n` + [o.address, o.price, o.size].join(' | ') + '\n\n' ); - /** * This is to not break the rate limit. It is to only send 1 message per second */ @@ -66,21 +56,10 @@ exports.send = ({ serviceName, newListings, notificationConfig, jobKey }) => { }, RATE_LIMIT_INTERVAL); }); }); - return Promise.all(promises); }; - -function shorten(str, len = 30) { - return str.length > len ? str.substring(0, len) + '...' : str; -} - -/** - * exported config is being used in the frontend to generate the fields - * incoming values will be the keys (and values) of the fields - * - */ -exports.config = { - id: __filename.slice(__dirname.length + 1, -3), +export const config = { + id: 'telegram', name: 'Telegram', readme: markdown2Html('lib/notification/adapter/telegram.md'), description: 'Fredy will send new listings to your mobile, using Telegram.', diff --git a/lib/notification/notify.js b/lib/notification/notify.js index 9df1446..2f22a8b 100755 --- a/lib/notification/notify.js +++ b/lib/notification/notify.js @@ -1,24 +1,24 @@ -const fs = require('fs'); +import fs from 'fs'; const path = './adapter'; /** Read every integration existing in ./adapter **/ -const adapter = fs - .readdirSync('./lib/notification/adapter') - .filter((file) => file.endsWith('.js')) - .map((integPath) => require(`${path}/${integPath}`)); +const adapter = await Promise.all( + fs + .readdirSync('./lib/notification/adapter') + .filter((file) => file.endsWith('.js')) + .map(async (integPath) => await import(`${path}/${integPath}`)) +); if (adapter.length === 0) { throw new Error('Please specify at least one notification provider'); } - -exports.send = (serviceName, newListings, notificationConfig, jobKey) => { +const findAdapter = (notificationAdapter) => { + return adapter.find((a) => a.config.id === notificationAdapter.id); +}; +export const send = (serviceName, newListings, notificationConfig, jobKey) => { //this is not being used in tests, therefore adapter are always set return notificationConfig .filter((notificationAdapter) => findAdapter(notificationAdapter) != null) .map((notificationAdapter) => findAdapter(notificationAdapter)) .map((a) => a.send({ serviceName, newListings, notificationConfig, jobKey })); }; - -const findAdapter = (notificationAdapter) => { - return adapter.find((a) => a.config.id === notificationAdapter.id); -}; diff --git a/lib/provider/einsAImmobilien.js b/lib/provider/einsAImmobilien.js index cb7427c..ccccedf 100755 --- a/lib/provider/einsAImmobilien.js +++ b/lib/provider/einsAImmobilien.js @@ -1,24 +1,18 @@ -const utils = require('../utils'); - +import utils from '../utils.js'; let appliedBlackList = []; - function normalize(o) { let size = `${o.size.replace(' Wohnfläche ', '').trim()}`; if (o.rooms != null) { size += ` / / ${o.rooms.trim()}`; } const link = `https://www.1a-immobilienmarkt.de/expose/${o.id}.html`; - return Object.assign(o, { size, link }); } - function applyBlacklist(o) { const titleNotBlacklisted = !utils.isOneOf(o.title, appliedBlackList); const descNotBlacklisted = !utils.isOneOf(o.description, appliedBlackList); - return titleNotBlacklisted && descNotBlacklisted; } - const config = { url: null, crawlContainer: '.tabelle', @@ -34,17 +28,14 @@ const config = { normalize: normalize, filter: applyBlacklist, }; - -exports.init = (sourceConfig, blacklist) => { +export const init = (sourceConfig, blacklist) => { config.enabled = sourceConfig.enabled; config.url = sourceConfig.url; appliedBlackList = blacklist || []; }; - -exports.metaInformation = { +export const metaInformation = { name: '1a Immobilien', baseUrl: 'https://www.1a-immobilienmarkt.de/', - id: __filename.slice(__dirname.length + 1, -3), + id: 'einsAImmobilien', }; - -exports.config = config; +export { config }; diff --git a/lib/provider/immobilienDe.js b/lib/provider/immobilienDe.js index 7e5e65b..95c56ce 100644 --- a/lib/provider/immobilienDe.js +++ b/lib/provider/immobilienDe.js @@ -1,15 +1,11 @@ -const utils = require('../utils'); - +import utils from '../utils.js'; let appliedBlackList = []; - function shortenLink(link) { return link.substring(0, link.indexOf('?')); } - function parseId(shortenedLink) { return shortenedLink.substring(shortenedLink.lastIndexOf('/') + 1); } - function normalize(o) { const id = parseId(shortenLink(o.link)); const size = o.size || 'N/A m²'; @@ -19,14 +15,11 @@ function normalize(o) { const link = shortenLink(o.link); return Object.assign(o, { id, price, size, title, address, link }); } - function applyBlacklist(o) { const titleNotBlacklisted = !utils.isOneOf(o.title, appliedBlackList); const descNotBlacklisted = !utils.isOneOf(o.description, appliedBlackList); - return titleNotBlacklisted && descNotBlacklisted; } - const config = { url: null, crawlContainer: '.estates_list .list_immo a._ref', @@ -43,17 +36,14 @@ const config = { normalize: normalize, filter: applyBlacklist, }; - -exports.init = (sourceConfig, blacklist) => { +export const init = (sourceConfig, blacklist) => { config.enabled = sourceConfig.enabled; config.url = sourceConfig.url; appliedBlackList = blacklist || []; }; - -exports.metaInformation = { +export const metaInformation = { name: 'Immobilien.de', baseUrl: 'https://www.immobilien.de/', - id: __filename.slice(__dirname.length + 1, -3), + id: 'immobilienDe', }; - -exports.config = config; +export { config }; diff --git a/lib/provider/immonet.js b/lib/provider/immonet.js index 08d097d..3c34593 100755 --- a/lib/provider/immonet.js +++ b/lib/provider/immonet.js @@ -1,7 +1,5 @@ -const utils = require('../utils'); - +import utils from '../utils.js'; let appliedBlackList = []; - function normalize(o) { const id = parseInt(o.id.substring(o.id.indexOf('_') + 1, o.id.length)); const size = o.size != null ? o.size.replace('Wohnfläche ', '') : 'N/A m²'; @@ -13,14 +11,11 @@ function normalize(o) { const link = `https://www.immonet.de/angebot/${id}`; return Object.assign(o, { id, address, price, size, title, link }); } - function applyBlacklist(o) { const titleNotBlacklisted = !utils.isOneOf(o.title, appliedBlackList); const descNotBlacklisted = !utils.isOneOf(o.description, appliedBlackList); - return titleNotBlacklisted && descNotBlacklisted; } - const config = { url: null, crawlContainer: '#result-list-stage .item', @@ -36,17 +31,14 @@ const config = { normalize: normalize, filter: applyBlacklist, }; - -exports.init = (sourceConfig, blacklist) => { +export const init = (sourceConfig, blacklist) => { config.enabled = sourceConfig.enabled; config.url = sourceConfig.url; appliedBlackList = blacklist || []; }; - -exports.metaInformation = { +export const metaInformation = { name: 'Immonet', baseUrl: 'https://www.immonet.de/', - id: __filename.slice(__dirname.length + 1, -3), + id: 'immonet', }; - -exports.config = config; +export { config }; diff --git a/lib/provider/immoscout.js b/lib/provider/immoscout.js index 4d81c2e..3eca506 100644 --- a/lib/provider/immoscout.js +++ b/lib/provider/immoscout.js @@ -1,22 +1,17 @@ -const utils = require('../utils'); - +import utils from '../utils.js'; let appliedBlackList = []; - function nullOrEmpty(val) { return val == null || val.length === 0; } - function normalize(o) { const title = nullOrEmpty(o.title) ? 'NO TITLE FOUND' : o.title.replace('NEU', ''); const address = nullOrEmpty(o.address) ? 'NO ADDRESS FOUND' : (o.address || '').replace(/\(.*\),.*$/, '').trim(); const link = `https://www.immobilienscout24.de${o.link.substring(o.link.indexOf('/expose'))}`; return Object.assign(o, { title, address, link }); } - function applyBlacklist(o) { return !utils.isOneOf(o.title, appliedBlackList); } - const config = { url: null, crawlContainer: '#resultListItems li.result-list__listing', @@ -33,17 +28,14 @@ const config = { normalize: normalize, filter: applyBlacklist, }; - -exports.init = (sourceConfig, blacklist) => { +export const init = (sourceConfig, blacklist) => { config.enabled = sourceConfig.enabled; config.url = sourceConfig.url; appliedBlackList = blacklist || []; }; - -exports.metaInformation = { +export const metaInformation = { name: 'Immoscout', baseUrl: 'https://www.immobilienscout24.de/', - id: __filename.slice(__dirname.length + 1, -3), + id: 'immoscout', }; - -exports.config = config; +export { config }; diff --git a/lib/provider/immoswp.js b/lib/provider/immoswp.js index 898a0a8..49d6d52 100755 --- a/lib/provider/immoswp.js +++ b/lib/provider/immoswp.js @@ -1,7 +1,5 @@ -const utils = require('../utils'); - +import utils from '../utils.js'; let appliedBlackList = []; - function normalize(o) { const id = o.id.substring(o.id.indexOf('-') + 1, o.id.length); const size = o.size || 'N/A m²'; @@ -12,14 +10,11 @@ function normalize(o) { const description = o.description; return Object.assign(o, { id, address, price, size, title, link, description }); } - function applyBlacklist(o) { const titleNotBlacklisted = !utils.isOneOf(o.title, appliedBlackList); const descNotBlacklisted = !utils.isOneOf(o.description, appliedBlackList); - return titleNotBlacklisted && descNotBlacklisted; } - const config = { url: null, crawlContainer: '.js-serp-item', @@ -36,17 +31,14 @@ const config = { normalize: normalize, filter: applyBlacklist, }; - -exports.init = (sourceConfig, blacklist) => { +export const init = (sourceConfig, blacklist) => { config.enabled = sourceConfig.enabled; config.url = sourceConfig.url; appliedBlackList = blacklist || []; }; - -exports.metaInformation = { +export const metaInformation = { name: 'Immo Südwest Presse', baseUrl: 'https://immo.swp.de/', - id: __filename.slice(__dirname.length + 1, -3), + id: 'immoswp', }; - -exports.config = config; +export { config }; diff --git a/lib/provider/immowelt.js b/lib/provider/immowelt.js index 40781bd..4210b56 100755 --- a/lib/provider/immowelt.js +++ b/lib/provider/immowelt.js @@ -1,18 +1,13 @@ -const utils = require('../utils'); - +import utils from '../utils.js'; let appliedBlackList = []; - function normalize(o) { return o; } - function applyBlacklist(o) { const titleNotBlacklisted = !utils.isOneOf(o.title, appliedBlackList); const descNotBlacklisted = !utils.isOneOf(o.description, appliedBlackList); - return titleNotBlacklisted && descNotBlacklisted; } - const config = { url: null, crawlContainer: "div[class^='EstateItem-']", @@ -29,16 +24,14 @@ const config = { normalize: normalize, filter: applyBlacklist, }; - -exports.init = (sourceConfig, blacklist) => { +export const init = (sourceConfig, blacklist) => { config.enabled = sourceConfig.enabled; config.url = sourceConfig.url; appliedBlackList = blacklist || []; }; -exports.metaInformation = { +export const metaInformation = { name: 'Immowelt', baseUrl: 'https://www.immowelt.de/', - id: __filename.slice(__dirname.length + 1, -3), + id: 'immowelt', }; - -exports.config = config; +export { config }; diff --git a/lib/provider/kleinanzeigen.js b/lib/provider/kleinanzeigen.js index f972e29..ea7c034 100755 --- a/lib/provider/kleinanzeigen.js +++ b/lib/provider/kleinanzeigen.js @@ -1,23 +1,17 @@ -const utils = require('../utils'); - +import utils from '../utils.js'; let appliedBlackList = []; let appliedBlacklistedDistricts = []; - function normalize(o) { const size = o.size || '--- m²'; - return Object.assign(o, { size }); } - function applyBlacklist(o) { const titleNotBlacklisted = !utils.isOneOf(o.title, appliedBlackList); const descNotBlacklisted = !utils.isOneOf(o.description, appliedBlackList); const isBlacklistedDistrict = appliedBlacklistedDistricts.length === 0 ? false : utils.isOneOf(o.description, appliedBlacklistedDistricts); - return !isBlacklistedDistrict && titleNotBlacklisted && descNotBlacklisted; } - const config = { url: null, crawlContainer: '#srchrslt-adtable .ad-listitem ', @@ -36,18 +30,15 @@ const config = { normalize: normalize, filter: applyBlacklist, }; - -exports.metaInformation = { +export const metaInformation = { name: 'Ebay Kleinanzeigen', baseUrl: 'https://www.ebay-kleinanzeigen.de/', - id: __filename.slice(__dirname.length + 1, -3), + id: 'kleinanzeigen', }; - -exports.init = (sourceConfig, blacklist, blacklistedDistricts) => { +export const init = (sourceConfig, blacklist, blacklistedDistricts) => { config.enabled = sourceConfig.enabled; config.url = sourceConfig.url; appliedBlacklistedDistricts = blacklistedDistricts || []; appliedBlackList = blacklist || []; }; - -exports.config = config; +export { config }; diff --git a/lib/provider/neubauKompass.js b/lib/provider/neubauKompass.js index 90721bd..94221f2 100755 --- a/lib/provider/neubauKompass.js +++ b/lib/provider/neubauKompass.js @@ -1,15 +1,11 @@ -const utils = require('../utils'); - +import utils from '../utils.js'; let appliedBlackList = []; - function normalize(o) { return o; } - function applyBlacklist(o) { return !utils.isOneOf(o.title, appliedBlackList); } - const config = { url: null, crawlContainer: '.nbk-container >div article', @@ -25,17 +21,14 @@ const config = { normalize: normalize, filter: applyBlacklist, }; - -exports.init = (sourceConfig, blacklist) => { +export const init = (sourceConfig, blacklist) => { config.enabled = sourceConfig.enabled; config.url = sourceConfig.url; appliedBlackList = blacklist || []; }; - -exports.metaInformation = { +export const metaInformation = { name: 'Neubau Kompass', baseUrl: 'https://www.neubaukompass.de/', - id: __filename.slice(__dirname.length + 1, -3), + id: 'neubauKompass', }; - -exports.config = config; +export { config }; diff --git a/lib/provider/wgGesucht.js b/lib/provider/wgGesucht.js index 19d67cf..e4c29f2 100755 --- a/lib/provider/wgGesucht.js +++ b/lib/provider/wgGesucht.js @@ -1,18 +1,13 @@ -const utils = require('../utils'); - +import utils from '../utils.js'; let appliedBlackList = []; - function normalize(o) { return o; } - function applyBlacklist(o) { const titleNotBlacklisted = !utils.isOneOf(o.title, appliedBlackList); const descNotBlacklisted = !utils.isOneOf(o.description, appliedBlackList); - return o.id != null && titleNotBlacklisted && descNotBlacklisted; } - const config = { url: null, crawlContainer: '#main_column .wgg_card', @@ -28,17 +23,14 @@ const config = { normalize: normalize, filter: applyBlacklist, }; - -exports.init = (sourceConfig, blacklist) => { +export const init = (sourceConfig, blacklist) => { config.enabled = sourceConfig.enabled; config.url = sourceConfig.url; appliedBlackList = blacklist || []; }; - -exports.metaInformation = { +export const metaInformation = { name: 'Wg gesucht', baseUrl: 'https://www.wg-gesucht.de/', - id: __filename.slice(__dirname.length + 1, -3), + id: 'wgGesucht', }; - -exports.config = config; +export { config }; diff --git a/lib/services/markdown.js b/lib/services/markdown.js index 24f1d2a..7ca10cf 100644 --- a/lib/services/markdown.js +++ b/lib/services/markdown.js @@ -1,6 +1,6 @@ -const markdown = require('markdown').markdown; -const fs = require('fs'); - -exports.markdown2Html = function markdown2Html(filePath) { +import markdown$0 from 'markdown'; +import fs from 'fs'; +const markdown = markdown$0.markdown; +export function markdown2Html(filePath) { return markdown.toHTML(fs.readFileSync(filePath, 'utf8')); -}; +} diff --git a/lib/services/queryStringMutator.js b/lib/services/queryStringMutator.js index 1354425..ddbae60 100644 --- a/lib/services/queryStringMutator.js +++ b/lib/services/queryStringMutator.js @@ -1,21 +1,9 @@ -const queryString = require('query-string'); - -/** - * for Fredy, it is important to sort search results by date, starting with the latest listing. if it is not sorted, we - * might never actually find the newest results, no matter how many pages we crawl. - * It has been written in the documentation, but obviously nobody reads docu theses days which is why it's been done - * automagically now. - * - * @param _url actual provider url containing the searchParams - * @param sortByDateParam param(s) indicating the correct sort order - * @returns {`${string}?${string}`} correctly formatted url - */ -module.exports = (_url, sortByDateParam) => { +import queryString from 'query-string'; +export default (_url, sortByDateParam) => { //if no mutation is necessary, just return the original url if (sortByDateParam == null) { return _url; } - const original = queryString.parseUrl(_url); const mutate = queryString.parse(sortByDateParam); return `${original.url}?${queryString.stringify({ ...original.query, ...mutate })}`; diff --git a/lib/services/requestDriver.js b/lib/services/requestDriver.js index 44808f7..9723918 100644 --- a/lib/services/requestDriver.js +++ b/lib/services/requestDriver.js @@ -1,19 +1,15 @@ -const fetch = require('node-fetch'); -const config = require('../../conf/config.json'); - -const { makeUrlResidential } = require('./scrapingAnt'); +import fetch from 'node-fetch'; +import { config } from '../utils.js'; +import { makeUrlResidential } from './scrapingAnt.js'; //if ScrapingAnt got blocked, this http status is returned const BLOCKED_HTTP_STATUS = 423; const NOT_FOUND_HTTP_STATUS = 404; const MAX_RETRIES_SCRAPING_ANT = 10; const EXPECTED_STATUS_CODES = [BLOCKED_HTTP_STATUS, NOT_FOUND_HTTP_STATUS]; - function makeDriver(headers = {}) { let cookies = ''; - async function scrapingAntDriver(context, callback, retryCounter = 0) { const proxyType = config.scrapingAnt?.proxy || 'datacenter'; - try { const url = proxyType === 'residential' ? makeUrlResidential(context.url) : context.url; const response = await fetch(url, { @@ -22,12 +18,10 @@ function makeDriver(headers = {}) { cookie: cookies, }, }); - const result = await response.text(); if (cookies.length === 0) { cookies = response.headers.raw()['set-cookie'] || []; } - callback(null, result); } catch (exception) { /* eslint-disable no-console */ @@ -36,7 +30,6 @@ function makeDriver(headers = {}) { callback(null, []); return; } - if (retryCounter <= MAX_RETRIES_SCRAPING_ANT) { retryCounter++; console.debug(`ScrapingAnt got blocked. Retrying ${retryCounter} / ${MAX_RETRIES_SCRAPING_ANT}`); @@ -48,7 +41,6 @@ function makeDriver(headers = {}) { /* eslint-enable no-console */ } } - /** * The regular request driver is taking care of everyting, that doesn't need to be scraped by ScrapingAnt (which is * everything != Immoscout as of writing this) @@ -57,7 +49,6 @@ function makeDriver(headers = {}) { if (context.url.toLowerCase().indexOf('scrapingant') !== -1) { return scrapingAntDriver(context, callback); } - try { const response = await fetch(context.url, { headers: { @@ -65,7 +56,6 @@ function makeDriver(headers = {}) { Cookie: cookies, }, }); - const result = await response.text(); callback(null, result); } catch (exception) { @@ -74,5 +64,4 @@ function makeDriver(headers = {}) { } }; } - -module.exports = makeDriver; +export default makeDriver; diff --git a/lib/services/scraper.js b/lib/services/scraper.js index ca65233..c968659 100755 --- a/lib/services/scraper.js +++ b/lib/services/scraper.js @@ -1,7 +1,6 @@ -const config = require('../../conf/config.json'); -const makeDriver = require('./requestDriver'); -const Xray = require('x-ray'); - +import { config } from '../utils.js'; +import makeDriver from './requestDriver.js'; +import Xray from 'x-ray'; class Scraper { constructor() { const filters = { @@ -9,38 +8,29 @@ class Scraper { trim: this._trim, int: this._int, }; - const headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.85 Safari/537.36', }; - if (config.scrapingAnt != null && config.scrapingAnt.apiKey != null) { headers['x-api-key'] = config.scrapingAnt.apiKey; } const driver = makeDriver(headers); - const xray = Xray({ filters }); xray.driver(driver); - this.xray = xray; } - get x() { return this.xray; } - _removeNewline(value) { return typeof value === 'string' ? value.replace(/\\n/g, '') : value; } - _trim(value) { return typeof value === 'string' ? value.replace(/\s+/g, ' ').trim() : value; } - _int(value) { return typeof value === 'string' ? parseInt(value, 10) : value; } } - -module.exports = new Scraper().x; +export default new Scraper().x; diff --git a/lib/services/scrapingAnt.js b/lib/services/scrapingAnt.js index bdd5a82..ee1df84 100644 --- a/lib/services/scrapingAnt.js +++ b/lib/services/scrapingAnt.js @@ -1,25 +1,19 @@ -const { metaInformation } = require('../provider/immoscout'); -//to better configure re-capture chose a random proxy each time we do a call -const config = require('../../conf/config.json'); - +import { metaInformation } from '../provider/immoscout.js'; +import { config } from '../utils.js'; const isImmoscout = (id) => { return id.toLowerCase() === metaInformation.id; }; - -exports.transformUrlForScrapingAnt = (url, id) => { +export const transformUrlForScrapingAnt = (url, id) => { if (isImmoscout(id)) { //only do calls to scrapingAnt when dealing with Immoscout url = `https://api.scrapingant.com/v1/general?url=${encodeURIComponent(url)}&proxy_type=datacenter`; } return url; }; - -exports.isScrapingAntApiKeySet = () => { +export const isScrapingAntApiKeySet = () => { return config.scrapingAnt != null && config.scrapingAnt.apiKey != null && config.scrapingAnt.apiKey.length > 0; }; - -exports.isImmoscout = isImmoscout; - -exports.makeUrlResidential = (url) => { +export const makeUrlResidential = (url) => { return url.replace('datacenter', 'residential'); }; +export { isImmoscout }; diff --git a/lib/services/security/hash.js b/lib/services/security/hash.js index 225c6e1..ca07ad4 100644 --- a/lib/services/security/hash.js +++ b/lib/services/security/hash.js @@ -1,3 +1,2 @@ -const crypto = require('crypto'); - -exports.hash = (x) => crypto.createHash('sha256').update(x, 'utf8').digest('hex'); +import crypto from 'crypto'; +export const hash = (x) => crypto.createHash('sha256').update(x, 'utf8').digest('hex'); diff --git a/lib/services/similarity-check/SimilarityCacheEntry.js b/lib/services/similarity-check/SimilarityCacheEntry.js index e9fcf42..65b32c7 100644 --- a/lib/services/similarity-check/SimilarityCacheEntry.js +++ b/lib/services/similarity-check/SimilarityCacheEntry.js @@ -1,27 +1,17 @@ -const stringSimilarity = require('string-similarity'); - +import stringSimilarity from 'string-similarity'; //if the score is higher than this, it will be considered a match const MAX_DICE_INDEX = 0.7; - -/** - * The similarity check is based on the dice coefficient. => https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient - * - * @type {module.SimilarityCacheEntry} - */ -module.exports = class SimilarityCacheEntry { +export default (class SimilarityCacheEntry { constructor(time) { this.time = time; this.values = []; } - setCacheEntry = (entry) => { this.values.push(entry); }; - getTime = () => { return this.time; }; - hasSimilarEntries = (value) => { if (this.values.length > 0) { for (let i = 0; i < this.values.length; i++) { @@ -33,4 +23,4 @@ module.exports = class SimilarityCacheEntry { } return false; }; -}; +}); diff --git a/lib/services/similarity-check/similarityCache.js b/lib/services/similarity-check/similarityCache.js index e6af41a..0e94819 100644 --- a/lib/services/similarity-check/similarityCache.js +++ b/lib/services/similarity-check/similarityCache.js @@ -1,63 +1,40 @@ -/** - * each job that runs scrapes all provider. This cache holds the titles of the found listing(s) and provides - * a similarity check. if this check returns true, it will not be forwarded to the notification adapter, thus - * the user won't see any duplicates - * - * The retention of this cache is per default 5 minutes, but can be smaller if the interval is > 5 mins. - * - * @type {module.SimilarityCacheEntry|{}} - */ -const SimilarityCacheEntry = require('./SimilarityCacheEntry'); -const config = require('../../../conf/config.json'); - +import SimilarityCacheEntry from './SimilarityCacheEntry.js'; +import { config } from '../../utils.js'; //5 minutes let retention = 5 * 60 * 1000; - const intervalInMs = config.interval * 60 * 1000; //an interval below 5 mins sounds crazy, but there are ppl out there doing crazy shit. if (intervalInMs <= retention) { retention = Math.floor(intervalInMs / 2); } - //jobid -> SimilarityCacheEntry const cache = {}; - let intervalId; - -exports.addCacheEntry = (jobId, value) => { - cache[jobId] = cache[jobId] || new SimilarityCacheEntry(Date.now()); - cache[jobId].setCacheEntry(value); -}; - -exports.hasSimilarEntries = (jobId, value) => { - if (cache[jobId] == null) { - return false; - } - - return cache[jobId].hasSimilarEntries(value); -}; - /** * cleanup */ intervalId = setInterval(() => { const keysToBeRemoved = []; const now = Date.now(); - Object.keys(cache).forEach((key) => { if (cache[key].getTime() + retention < now) { keysToBeRemoved.push(key); } }); - if (keysToBeRemoved.length > 0) { keysToBeRemoved.forEach((key) => delete cache[key]); } }, 10000); - -/** - * mostly used for tests - */ -exports.stopCacheCleanup = () => { +export const addCacheEntry = (jobId, value) => { + cache[jobId] = cache[jobId] || new SimilarityCacheEntry(Date.now()); + cache[jobId].setCacheEntry(value); +}; +export const hasSimilarEntries = (jobId, value) => { + if (cache[jobId] == null) { + return false; + } + return cache[jobId].hasSimilarEntries(value); +}; +export const stopCacheCleanup = () => { clearInterval(intervalId); }; diff --git a/lib/services/storage/LowDashAdapter.js b/lib/services/storage/LowDashAdapter.js new file mode 100644 index 0000000..e113496 --- /dev/null +++ b/lib/services/storage/LowDashAdapter.js @@ -0,0 +1,8 @@ +import lodash from 'lodash'; +import { LowSync } from 'lowdb'; +export default class LowdashAdapter extends LowSync { + constructor(adapter) { + super(adapter); + this.chain = lodash.chain(this).get('data'); + } +} diff --git a/lib/services/storage/jobStorage.js b/lib/services/storage/jobStorage.js index adb5b12..a99d66f 100644 --- a/lib/services/storage/jobStorage.js +++ b/lib/services/storage/jobStorage.js @@ -1,28 +1,30 @@ -const path = require('path'); -const DB_PATH = path.dirname(require.main.filename) + '/db/jobs.json'; -const FileSync = require('lowdb/adapters/FileSync'); -const adapter = new FileSync(DB_PATH); -const low = require('lowdb'); -const db = low(adapter); -const { nanoid } = require('nanoid'); -const listingStorage = require('./listingsStorage'); +import { JSONFileSync } from 'lowdb/node'; +import { nanoid } from 'nanoid'; +import * as listingStorage from './listingsStorage.js'; +import { getDirName } from '../../utils.js'; +import path from 'path'; +import LowdashAdapter from './LowDashAdapter.js'; -db.defaults({ jobs: [] }).write(); +const file = path.join(getDirName(), '../', 'db/jobs.json'); +const adapter = new JSONFileSync(file); +const db = new LowdashAdapter(adapter); -exports.upsertJob = ({ jobId, name, blacklist = [], enabled = true, provider, notificationAdapter, userId }) => { +db.read(); + +db.data ||= { jobs: [] }; + +export const upsertJob = ({ jobId, name, blacklist = [], enabled = true, provider, notificationAdapter, userId }) => { const currentJob = jobId == null ? null - : db + : db.chain .get('jobs') .find((job) => job.id === jobId) .value(); - - const jobs = db + const jobs = db.chain .get('jobs') - .value() - .filter((job) => job.id !== jobId); - + .filter((job) => job.id !== jobId) + .value(); jobs.push({ id: jobId || nanoid(), //make sure to not overwrite the user id in case an admin changes the job @@ -33,57 +35,55 @@ exports.upsertJob = ({ jobId, name, blacklist = [], enabled = true, provider, no provider, notificationAdapter, }); - - db.set('jobs', jobs).write(); + db.chain.set('jobs', jobs).value(); + db.write(); }; - -exports.getJob = (jobId) => { - const job = db +export const getJob = (jobId) => { + const job = db.chain .get('jobs') .find((job) => job.id === jobId) .value(); - if (job == null) { return null; } - return { ...job, numberOfFoundListings: listingStorage.getNumberOfAllKnownListings(job.id).length, }; }; - -exports.setJobStatus = ({ jobId, status }) => { - db.get('jobs') +export const setJobStatus = ({ jobId, status }) => { + db.chain + .get('jobs') .find((job) => job.id === jobId) .assign({ enabled: status }) - .write(); + .value(); + db.write(); }; - -exports.removeJob = (jobId) => { +export const removeJob = (jobId) => { listingStorage.removeListings(jobId); - db.get('jobs') + db.chain + .get('jobs') .remove((job) => job.id === jobId) - .write(); + .value(); + db.write(); }; - -exports.removeJobsByUserId = (userId) => { - db.get('jobs') - .value() +export const removeJobsByUserId = (userId) => { + db.chain + .get('jobs') .filter((job) => job.userId === userId) .forEach((job) => listingStorage.removeListings(job.id)); - - db.get('jobs') - .remove((job) => job.userId === userId) - .write(); -}; - -exports.getJobs = () => { - return db + db.chain + .get('jobs') + .remove((job) => job.userId === userId) + .value(); + db.write(); +}; +export const getJobs = () => { + return db.chain .get('jobs') - .value() .map((job) => ({ ...job, numberOfFoundListings: listingStorage.getNumberOfAllKnownListings(job.id), - })); + })) + .value(); }; diff --git a/lib/services/storage/listingsStorage.js b/lib/services/storage/listingsStorage.js index c25632e..dd3ec5c 100755 --- a/lib/services/storage/listingsStorage.js +++ b/lib/services/storage/listingsStorage.js @@ -1,10 +1,15 @@ -const path = require('path'); +import { JSONFileSync } from 'lowdb/node'; +import { getDirName } from '../../utils.js'; +import path from 'path'; +import LowdashAdapter from './LowDashAdapter.js'; -const DB_PATH = path.dirname(require.main.filename) + '/db/jobListingData.json'; -const FileSync = require('lowdb/adapters/FileSync'); -const adapter = new FileSync(DB_PATH); -const low = require('lowdb'); -const db = low(adapter); +const file = path.join(getDirName(), '../', 'db/jobListingData.json'); +const adapter = new JSONFileSync(file); +const db = new LowdashAdapter(adapter); + +db.read(); + +db.data ||= {}; const buildKey = (jobKey, providerId, endpoint) => { let key = `${jobKey}`; @@ -19,35 +24,31 @@ const buildKey = (jobKey, providerId, endpoint) => { } return key; }; - -exports.getNumberOfAllKnownListings = (jobId) => { - const data = db.get(`${jobId}.providerData`).value() || {}; +export const getNumberOfAllKnownListings = (jobId) => { + const data = db.chain.get(`${jobId}.providerData`).value() || {}; return Object.values(data) .map((values) => Object.keys(values).length) .reduce((accumulator, currentValue) => accumulator + currentValue, 0); }; - -exports.getListingProviderDataForAnalytics = (jobId) => { +export const getListingProviderDataForAnalytics = (jobId) => { const key = buildKey(jobId, 'providerData'); - return db.get(key).value() || {}; + return db.chain.get(key).value() || {}; }; - -exports.getKnownListings = (jobId, providerId) => { +export const getKnownListings = (jobId, providerId) => { const providerListingsKey = buildKey(jobId, 'providerData', providerId, 'listings'); - return db.get(providerListingsKey).value() || {}; + return db.chain.get(providerListingsKey).value() || {}; }; - -exports.setKnownListings = (jobId, providerId, listings) => { +export const setKnownListings = (jobId, providerId, listings) => { const providerListingsKey = buildKey(jobId, 'providerData', providerId, 'listings'); - - return db.set(providerListingsKey, listings).write(); + db.chain.set(providerListingsKey, listings).value(); + return db.write(); }; - -exports.setLastJobExecution = (jobId) => { +export const setLastJobExecution = (jobId) => { const key = buildKey(jobId, null, 'lastExecution'); - return db.set(key, Date.now()).write(); + db.chain.set(key, Date.now()).value(); + return db.write(); }; - -exports.removeListings = (jobId) => { - db.unset(jobId).write(); +export const removeListings = (jobId) => { + db.chain.unset(jobId).value(); + db.write(); }; diff --git a/lib/services/storage/userStorage.js b/lib/services/storage/userStorage.js index 87f0b90..4647193 100644 --- a/lib/services/storage/userStorage.js +++ b/lib/services/storage/userStorage.js @@ -1,14 +1,17 @@ -const path = require('path'); -const DB_PATH = path.dirname(require.main.filename) + '/db/users.json'; -const FileSync = require('lowdb/adapters/FileSync'); -const adapter = new FileSync(DB_PATH); -const low = require('lowdb'); -const db = low(adapter); -const hasher = require('../security/hash'); -const { nanoid } = require('nanoid'); -const jobStorage = require('./jobStorage'); +import { JSONFileSync } from 'lowdb/node'; +import { getDirName } from '../../utils.js'; +import * as hasher from '../security/hash.js'; +import { nanoid } from 'nanoid'; +import * as jobStorage from './jobStorage.js'; +import path from 'path'; +import LowdashAdapter from './LowDashAdapter.js'; -db.defaults({ +const file = path.join(getDirName(), '../', 'db/users.json'); +const adapter = new JSONFileSync(file); +const db = new LowdashAdapter(adapter); + +db.read(); +db.data ||= { user: [ //you probably want to change the default password ;) { @@ -20,11 +23,11 @@ db.defaults({ isDemo: false, }, ], -}).write(); +}; -exports.getUsers = (withPassword) => { +export const getUsers = (withPassword) => { const jobs = jobStorage.getJobs(); - return db + return db.chain .get('user') .value() .map((user) => ({ @@ -34,13 +37,12 @@ exports.getUsers = (withPassword) => { numberOfJobs: jobs.filter((job) => job.userId === user.id).length, })); }; - -exports.getUser = (id) => { +export const getUser = (id) => { const jobs = jobStorage.getJobs(); - const user = db + const user = db.chain .get('user') - .value() - .find((user) => user.id === id); + .find((user) => user.id === id) + .value(); if (user == null) { return null; } @@ -49,13 +51,11 @@ exports.getUser = (id) => { numberOfJobs: jobs.filter((job) => job.userId === user.id).length, }; }; - -exports.upsertUser = ({ username, password, userId, isAdmin }) => { - const user = db +export const upsertUser = ({ username, password, userId, isAdmin }) => { + const user = db.chain .get('user') - .value() - .filter((u) => u.id !== userId); - + .filter((u) => u.id !== userId) + .value(); user.push({ id: userId || nanoid(), username, @@ -63,21 +63,24 @@ exports.upsertUser = ({ username, password, userId, isAdmin }) => { password: hasher.hash(password), isAdmin, }); - - db.set('user', user).write(); + db.chain.set('user', user).value(); + db.write(); }; - -exports.setLastLoginToNow = ({ userId }) => { - db.get('user') +export const setLastLoginToNow = ({ userId }) => { + db.chain + .get('user') .find((u) => u.id === userId) .assign({ lastLogin: Date.now() }) - .write(); + .value(); + db.write(); }; - -exports.removeUser = (userId) => { - const user = db.get('user').value(); - db.set( - 'user', - user.filter((u) => u.id !== userId) - ).write(); +export const removeUser = (userId) => { + const user = db.chain.get('user').value(); + db.chain + .set( + 'user', + user.filter((u) => u.id !== userId) + ) + .value(); + db.write(); }; diff --git a/lib/utils.js b/lib/utils.js index ad96040..52d6230 100755 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,17 +1,18 @@ +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { readFile } from 'fs/promises'; + function isOneOf(word, arr) { if (arr == null || arr.length === 0) { return false; } const expression = String.raw`\b(${arr.join('|')})\b`; const blacklist = new RegExp(expression, 'ig'); - return blacklist.test(word); } - function nullOrEmpty(val) { return val == null || val.length === 0; } - function timeStringToMs(timeString, now) { const d = new Date(now); const parts = timeString.split(':'); @@ -20,17 +21,31 @@ function timeStringToMs(timeString, now) { d.setSeconds(0); return d.getTime(); } - function duringWorkingHoursOrNotSet(config, now) { const { workingHours } = config; if (workingHours == null || nullOrEmpty(workingHours.from) || nullOrEmpty(workingHours.to)) { return true; } - const toDate = timeStringToMs(workingHours.to, now); const fromDate = timeStringToMs(workingHours.from, now); - return fromDate <= now && toDate >= now; } -module.exports = { isOneOf, nullOrEmpty, duringWorkingHoursOrNotSet }; +function getDirName() { + return dirname(fileURLToPath(import.meta.url)); +} + +const config = JSON.parse(await readFile(new URL('../conf/config.json', import.meta.url))); + +export { isOneOf }; +export { nullOrEmpty }; +export { duringWorkingHoursOrNotSet }; +export { getDirName }; +export { config }; +export default { + isOneOf, + nullOrEmpty, + duringWorkingHoursOrNotSet, + getDirName, + config, +}; diff --git a/package.json b/package.json index be10305..fabdca8 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fredy", - "version": "6.0.2", + "version": "7.0.0", "description": "[F]ind [R]eal [E]states [d]amn eas[y].", "scripts": { "start": "node index.js", @@ -8,7 +8,7 @@ "ui": "rm -rf ./ui/public/* && vite", "prod": "yarn && vite build --emptyOutDir", "format": "prettier --write lib/**/*.js ui/src/**/*.js test/**/*.js *.js --single-quote --print-width 120", - "test": "mocha --timeout 3000000 test/**/*.test.js", + "test": "mocha --loader=esmock --timeout 3000000 test/**/*.test.js", "lint": "eslint ./index.js ./lib/**/*.js ./test/**/*.js" }, "husky": { @@ -16,6 +16,7 @@ "pre-commit": "lint-staged" } }, + "type": "module", "lint-staged": { "*.js": [ "eslint ./index.js ./lib/**/*.js ./test/**/*.js", @@ -58,18 +59,19 @@ "@rematch/loading": "2.1.2", "@sendgrid/mail": "7.7.0", "@vitejs/plugin-react": "3.1.0", - "better-sqlite3": "8.1.0", - "body-parser": "1.20.1", + "better-sqlite3": "8.2.0", + "body-parser": "1.20.2", "cookie-session": "2.0.0", "handlebars": "4.7.7", "highcharts": "10.3.3", - "highcharts-react-official": "3.1.0", - "lowdb": "1.0.0", + "highcharts-react-official": "3.2.0", + "lodash": "^4.17.21", + "lowdb": "5.1.0", "markdown": "^0.5.0", - "nanoid": "3.3.3", - "node-fetch": "2.6.9", - "node-mailjet": "3.3.13", - "query-string": "7.1.3", + "nanoid": "4.0.1", + "node-fetch": "3.3.1", + "node-mailjet": "6.0.2", + "query-string": "8.1.0", "react": "18.2.0", "react-dom": "18.2.0", "react-redux": "8.0.5", @@ -83,25 +85,25 @@ "serve-static": "1.15.0", "slack": "11.0.2", "string-similarity": "^4.0.4", - "vite": "4.1.1", + "vite": "4.1.4", "x-ray": "2.3.4" }, "devDependencies": { - "@babel/core": "7.20.12", - "@babel/eslint-parser": "^7.19.1", + "esmock": "2.1.0", + "@babel/core": "7.21.0", + "@babel/eslint-parser": "7.19.1", "@babel/preset-env": "7.20.2", "@babel/preset-react": "7.18.6", "chai": "4.3.7", - "eslint": "8.34.0", - "eslint-config-prettier": "8.6.0", + "eslint": "8.36.0", + "eslint-config-prettier": "8.7.0", "eslint-plugin-react": "7.32.2", "history": "5.3.0", "husky": "4.3.8", "less": "4.1.3", - "lint-staged": "13.1.2", + "lint-staged": "13.2.0", "mocha": "10.2.0", "prettier": "2.8.4", - "proxyquire": "2.1.3", "redux-logger": "3.0.6" } } diff --git a/test/mocks/mockNotification.js b/test/mocks/mockNotification.js index 6ff56d3..72b4e95 100644 --- a/test/mocks/mockNotification.js +++ b/test/mocks/mockNotification.js @@ -1,12 +1,10 @@ -module.exports = { - _tmpStore: {}, +let tmpStore = {}; - send: (serviceName, payload) => { - this._tmpStore = { serviceName, payload }; - return [Promise.resolve()]; - }, - - get: () => { - return this._tmpStore; - }, +export const send = (serviceName, payload) => { + tmpStore = { serviceName, payload }; + return [Promise.resolve()]; +}; + +export const get = () => { + return tmpStore; }; diff --git a/test/mocks/mockStore.js b/test/mocks/mockStore.js index 39623a2..df9354e 100644 --- a/test/mocks/mockStore.js +++ b/test/mocks/mockStore.js @@ -1,11 +1,8 @@ const db = {}; - -exports.setKnownListings = (jobKey, providerId, listings) => { +export const setKnownListings = (jobKey, providerId, listings) => { if (!Array.isArray(listings)) throw Error('Not a valid array'); - db[providerId] = listings; }; - -exports.getKnownListings = (jobKey, providerId) => { +export const getKnownListings = (jobKey, providerId) => { return db[providerId] || []; }; diff --git a/test/provider/einsAImmobilien.test.js b/test/provider/einsAImmobilien.test.js index 18b8a7c..c5de616 100644 --- a/test/provider/einsAImmobilien.test.js +++ b/test/provider/einsAImmobilien.test.js @@ -1,35 +1,25 @@ -const similarityCache = require('../../lib/services/similarity-check/similarityCache'); -const mockNotification = require('../mocks/mockNotification'); -const providerConfig = require('./testProvider.json'); -const mockStore = require('../mocks/mockStore'); -const proxyquire = require('proxyquire').noCallThru(); -const expect = require('chai').expect; -const provider = require('../../lib/provider/einsAImmobilien'); +import * as similarityCache from '../../lib/services/similarity-check/similarityCache.js'; +import { get } from '../mocks/mockNotification.js'; +import { providerConfig, mockFredy } from '../utils.js'; +import chai from 'chai'; +import * as provider from '../../lib/provider/einsAImmobilien.js'; + +const expect = chai.expect; describe('#einsAImmobilien testsuite()', () => { after(() => { similarityCache.stopCacheCleanup(); }); - provider.init(providerConfig.einsAImmobilien, [], []); - - const Fredy = proxyquire('../../lib/FredyRuntime', { - './services/storage/listingsStorage': { - ...mockStore, - }, - './notification/notify': mockNotification, - }); - it('should test einsAImmobilien provider', async () => { + const Fredy = await mockFredy(); return await new Promise((resolve) => { const fredy = new Fredy(provider.config, null, provider.metaInformation.id, 'einsAImmobilien', similarityCache); fredy.execute().then((listings) => { expect(listings).to.be.a('array'); - - const notificationObj = mockNotification.get(); + const notificationObj = get(); expect(notificationObj).to.be.a('object'); expect(notificationObj.serviceName).to.equal('einsAImmobilien'); - notificationObj.payload.forEach((notify) => { /** check the actual structure **/ expect(notify.id).to.be.a('number'); @@ -37,7 +27,6 @@ describe('#einsAImmobilien testsuite()', () => { expect(notify.size).to.be.a('string'); expect(notify.title).to.be.a('string'); expect(notify.link).to.be.a('string'); - /** check the values if possible **/ expect(notify.size).to.be.not.empty; expect(notify.title).to.be.not.empty; diff --git a/test/provider/immobilienDe.test.js b/test/provider/immobilienDe.test.js index 8582bc8..3ee6782 100644 --- a/test/provider/immobilienDe.test.js +++ b/test/provider/immobilienDe.test.js @@ -1,31 +1,21 @@ -const similarityCache = require('../../lib/services/similarity-check/similarityCache'); -const mockNotification = require('../mocks/mockNotification'); -const providerConfig = require('./testProvider.json'); -const mockStore = require('../mocks/mockStore'); -const proxyquire = require('proxyquire').noCallThru(); -const expect = require('chai').expect; -const provider = require('../../lib/provider/immobilienDe'); - +import * as similarityCache from '../../lib/services/similarity-check/similarityCache.js'; +import { get } from '../mocks/mockNotification.js'; +import { providerConfig, mockFredy } from '../utils.js'; +import chai from 'chai'; +import * as provider from '../../lib/provider/immobilienDe.js'; +const expect = chai.expect; describe('#immobilien.de testsuite()', () => { after(() => { similarityCache.stopCacheCleanup(); }); - provider.init(providerConfig.immobilienDe, [], []); - const Fredy = proxyquire('../../lib/FredyRuntime', { - './services/storage/listingsStorage': { - ...mockStore, - }, - './notification/notify': mockNotification, - }); - it('should test immobilien.de provider', async () => { + const Fredy = await mockFredy(); return await new Promise((resolve) => { const fredy = new Fredy(provider.config, null, provider.metaInformation.id, 'test1', similarityCache); fredy.execute().then((listing) => { expect(listing).to.be.a('array'); - - const notificationObj = mockNotification.get(); + const notificationObj = get(); expect(notificationObj).to.be.a('object'); expect(notificationObj.serviceName).to.equal('immobilienDe'); notificationObj.payload.forEach((notify) => { @@ -36,7 +26,6 @@ describe('#immobilien.de testsuite()', () => { expect(notify.title).to.be.a('string'); expect(notify.link).to.be.a('string'); expect(notify.address).to.be.a('string'); - /** check the values if possible **/ expect(notify.price).that.does.include('€'); expect(notify.size).that.does.include('m²'); diff --git a/test/provider/immonet.test.js b/test/provider/immonet.test.js index 23eb910..a57be7b 100644 --- a/test/provider/immonet.test.js +++ b/test/provider/immonet.test.js @@ -1,34 +1,23 @@ -const similarityCache = require('../../lib/services/similarity-check/similarityCache'); -const mockNotification = require('../mocks/mockNotification'); -const providerConfig = require('./testProvider.json'); -const mockStore = require('../mocks/mockStore'); -const proxyquire = require('proxyquire').noCallThru(); -const expect = require('chai').expect; -const provider = require('../../lib/provider/immonet'); - +import * as similarityCache from '../../lib/services/similarity-check/similarityCache.js'; +import { get } from '../mocks/mockNotification.js'; +import { mockFredy, providerConfig } from '../utils.js'; +import chai from 'chai'; +import * as provider from '../../lib/provider/immonet.js'; +const expect = chai.expect; describe('#immonet testsuite()', () => { after(() => { similarityCache.stopCacheCleanup(); }); - provider.init(providerConfig.immonet, [], []); - const Fredy = proxyquire('../../lib/FredyRuntime', { - './services/storage/listingsStorage': { - ...mockStore, - }, - './notification/notify': mockNotification, - }); - it('should test immonet provider', async () => { + const Fredy = await mockFredy(); return await new Promise((resolve) => { const fredy = new Fredy(provider.config, null, provider.metaInformation.id, 'immonet', similarityCache); fredy.execute().then((listing) => { expect(listing).to.be.a('array'); - - const notificationObj = mockNotification.get(); + const notificationObj = get(); expect(notificationObj).to.be.a('object'); expect(notificationObj.serviceName).to.equal('immonet'); - notificationObj.payload.forEach((notify) => { /** check the actual structure **/ expect(notify.id).to.be.a('number'); @@ -37,7 +26,6 @@ describe('#immonet testsuite()', () => { expect(notify.title).to.be.a('string'); expect(notify.link).to.be.a('string'); expect(notify.address).to.be.a('string'); - /** check the values if possible **/ expect(notify.price).that.does.include('€'); expect(notify.size).that.does.include('m²'); diff --git a/test/provider/immoscout.test.js b/test/provider/immoscout.test.js index 1d95cb1..f94503b 100644 --- a/test/provider/immoscout.test.js +++ b/test/provider/immoscout.test.js @@ -1,25 +1,17 @@ -const similarityCache = require('../../lib/services/similarity-check/similarityCache'); -const mockNotification = require('../mocks/mockNotification'); -const providerConfig = require('./testProvider.json'); -const mockStore = require('../mocks/mockStore'); -const proxyquire = require('proxyquire').noCallThru(); -const expect = require('chai').expect; -const provider = require('../../lib/provider/immoscout'); -const scrapingAnt = require('../../lib/services/scrapingAnt'); - +import * as similarityCache from '../../lib/services/similarity-check/similarityCache.js'; +import { get } from '../mocks/mockNotification.js'; +import { mockFredy, providerConfig } from '../utils.js'; +import chai from 'chai'; +import * as provider from '../../lib/provider/immoscout.js'; +import * as scrapingAnt from '../../lib/services/scrapingAnt.js'; +const expect = chai.expect; describe('#immoscout testsuite()', () => { after(() => { similarityCache.stopCacheCleanup(); }); provider.init(providerConfig.immoscout, [], []); - const Fredy = proxyquire('../../lib/FredyRuntime', { - './services/storage/listingsStorage': { - ...mockStore, - }, - './notification/notify': mockNotification, - }); - it('should test immoscout provider', async () => { + const Fredy = await mockFredy(); return await new Promise((resolve) => { if (!scrapingAnt.isScrapingAntApiKeySet()) { /* eslint-disable no-console */ @@ -28,15 +20,12 @@ describe('#immoscout testsuite()', () => { resolve(); return; } - const fredy = new Fredy(provider.config, null, provider.metaInformation.id, 'immoscout', similarityCache); fredy.execute().then((listing) => { expect(listing).to.be.a('array'); - - const notificationObj = mockNotification.get(); + const notificationObj = get(); expect(notificationObj).to.be.a('object'); expect(notificationObj.serviceName).to.equal('immoscout'); - notificationObj.payload.forEach((notify) => { /** check the actual structure **/ expect(notify.id).to.be.a('number'); @@ -45,7 +34,6 @@ describe('#immoscout testsuite()', () => { expect(notify.title).to.be.a('string'); expect(notify.link).to.be.a('string'); expect(notify.address).to.be.a('string'); - /** check the values if possible **/ expect(notify.price).that.does.include('€'); expect(notify.size).that.does.include('m²'); diff --git a/test/provider/immoswp.test.js b/test/provider/immoswp.test.js index 31c3a04..6551f98 100644 --- a/test/provider/immoswp.test.js +++ b/test/provider/immoswp.test.js @@ -1,34 +1,23 @@ -const similarityCache = require('../../lib/services/similarity-check/similarityCache'); -const mockNotification = require('../mocks/mockNotification'); -const providerConfig = require('./testProvider.json'); -const mockStore = require('../mocks/mockStore'); -const proxyquire = require('proxyquire').noCallThru(); -const expect = require('chai').expect; -const provider = require('../../lib/provider/immoswp'); - +import * as similarityCache from '../../lib/services/similarity-check/similarityCache.js'; +import { get } from '../mocks/mockNotification.js'; +import { mockFredy, providerConfig } from '../utils.js'; +import chai from 'chai'; +import * as provider from '../../lib/provider/immoswp.js'; +const expect = chai.expect; describe('#immoswp testsuite()', () => { after(() => { similarityCache.stopCacheCleanup(); }); - provider.init(providerConfig.immoswp, [], []); - const Fredy = proxyquire('../../lib/FredyRuntime', { - './services/storage/listingsStorage': { - ...mockStore, - }, - './notification/notify': mockNotification, - }); - it('should test immoswp provider', async () => { + const Fredy = await mockFredy(); return await new Promise((resolve) => { const fredy = new Fredy(provider.config, null, provider.metaInformation.id, 'immoswp', similarityCache); fredy.execute().then((listing) => { expect(listing).to.be.a('array'); - - const notificationObj = mockNotification.get(); + const notificationObj = get(); expect(notificationObj).to.be.a('object'); expect(notificationObj.serviceName).to.equal('immoswp'); - notificationObj.payload.forEach((notify) => { /** check the actual structure **/ expect(notify.id).to.be.a('string'); @@ -37,7 +26,6 @@ describe('#immoswp testsuite()', () => { expect(notify.title).to.be.a('string'); expect(notify.link).to.be.a('string'); expect(notify.address).to.be.a('string'); - /** check the values if possible **/ expect(notify.price).that.does.include('€'); expect(notify.title).to.be.not.empty; diff --git a/test/provider/immowelt.test.js b/test/provider/immowelt.test.js index c5097b3..d28115d 100644 --- a/test/provider/immowelt.test.js +++ b/test/provider/immowelt.test.js @@ -1,42 +1,30 @@ -const similarityCache = require('../../lib/services/similarity-check/similarityCache'); -const mockNotification = require('../mocks/mockNotification'); -const providerConfig = require('./testProvider.json'); -const mockStore = require('../mocks/mockStore'); -const proxyquire = require('proxyquire').noCallThru(); -const expect = require('chai').expect; -const provider = require('../../lib/provider/immowelt'); - +import * as similarityCache from '../../lib/services/similarity-check/similarityCache.js'; +import { get } from '../mocks/mockNotification.js'; +import { mockFredy, providerConfig } from '../utils.js'; +import chai from 'chai'; +import * as provider from '../../lib/provider/immowelt.js'; +const expect = chai.expect; describe('#immowelt testsuite()', () => { after(() => { similarityCache.stopCacheCleanup(); }); it('should test immowelt provider', async () => { + const Fredy = await mockFredy(); provider.init(providerConfig.immowelt, [], []); - const Fredy = proxyquire('../../lib/FredyRuntime', { - './services/storage/listingsStorage': { - ...mockStore, - }, - './notification/notify': mockNotification, - }); - return await new Promise((resolve) => { const fredy = new Fredy(provider.config, null, provider.metaInformation.id, 'immowelt', similarityCache); fredy.execute().then((listing) => { expect(listing).to.be.a('array'); - - const notificationObj = mockNotification.get(); + const notificationObj = get(); expect(notificationObj).to.be.a('object'); expect(notificationObj.serviceName).to.equal('immowelt'); - notificationObj.payload.forEach((notify) => { /** check the actual structure **/ expect(notify.id).to.be.a('string'); expect(notify.price).to.be.a('string'); expect(notify.title).to.be.a('string'); - expect(notify.link).to.be.a('string'); expect(notify.address).to.be.a('string'); - /** check the values if possible **/ if (notify.size != null && notify.size.trim().toLowerCase() !== 'k.a.') { expect(notify.size).that.does.include('m²'); diff --git a/test/provider/kleinanzeigen.test.js b/test/provider/kleinanzeigen.test.js index 98006e9..09fcb5b 100644 --- a/test/provider/kleinanzeigen.test.js +++ b/test/provider/kleinanzeigen.test.js @@ -1,40 +1,29 @@ -const similarityCache = require('../../lib/services/similarity-check/similarityCache'); -const mockNotification = require('../mocks/mockNotification'); -const providerConfig = require('./testProvider.json'); -const mockStore = require('../mocks/mockStore'); -const proxyquire = require('proxyquire').noCallThru(); -const expect = require('chai').expect; -const provider = require('../../lib/provider/kleinanzeigen'); - +import * as similarityCache from '../../lib/services/similarity-check/similarityCache.js'; +import { get } from '../mocks/mockNotification.js'; +import { mockFredy, providerConfig } from '../utils.js'; +import chai from 'chai'; +import * as provider from '../../lib/provider/kleinanzeigen.js'; +const expect = chai.expect; describe('#kleinanzeigen testsuite()', () => { after(() => { similarityCache.stopCacheCleanup(); }); it('should test kleinanzeigen provider', async () => { + const Fredy = await mockFredy(); provider.init(providerConfig.kleinanzeigen, [], []); - const Fredy = proxyquire('../../lib/FredyRuntime', { - './services/storage/listingsStorage': { - ...mockStore, - }, - './notification/notify': mockNotification, - }); - return await new Promise((resolve) => { const fredy = new Fredy(provider.config, null, provider.metaInformation.id, 'kleinanzeigen', similarityCache); fredy.execute().then((listing) => { expect(listing).to.be.a('array'); - - const notificationObj = mockNotification.get(); + const notificationObj = get(); expect(notificationObj).to.be.a('object'); expect(notificationObj.serviceName).to.equal('kleinanzeigen'); - notificationObj.payload.forEach((notify) => { /** check the actual structure **/ expect(notify.id).to.be.a('number'); expect(notify.title).to.be.a('string'); expect(notify.link).to.be.a('string'); expect(notify.address).to.be.a('string'); - /** check the values if possible **/ expect(notify.title).to.be.not.empty; expect(notify.link).that.does.include('https://www.ebay-kleinanzeigen.de'); diff --git a/test/provider/neubauKompass.test.js b/test/provider/neubauKompass.test.js index 66a8ac4..a8797c3 100644 --- a/test/provider/neubauKompass.test.js +++ b/test/provider/neubauKompass.test.js @@ -1,41 +1,29 @@ -const similarityCache = require('../../lib/services/similarity-check/similarityCache'); -const mockNotification = require('../mocks/mockNotification'); -const providerConfig = require('./testProvider.json'); -const mockStore = require('../mocks/mockStore'); -const proxyquire = require('proxyquire').noCallThru(); -const expect = require('chai').expect; -const provider = require('../../lib/provider/neubauKompass'); - +import * as similarityCache from '../../lib/services/similarity-check/similarityCache.js'; +import { get } from '../mocks/mockNotification.js'; +import { mockFredy, providerConfig } from '../utils.js'; +import chai from 'chai'; +import * as provider from '../../lib/provider/neubauKompass.js'; +const expect = chai.expect; describe('#neubauKompass testsuite()', () => { after(() => { similarityCache.stopCacheCleanup(); }); provider.init(providerConfig.neubauKompass, [], []); - const Fredy = proxyquire('../../lib/FredyRuntime', { - './services/storage/listingsStorage': { - ...mockStore, - }, - './notification/notify': mockNotification, - }); - it('should test neubauKompass provider', async () => { + const Fredy = await mockFredy(); return await new Promise((resolve) => { const fredy = new Fredy(provider.config, null, provider.metaInformation.id, 'neubauKompass', similarityCache); fredy.execute().then((listing) => { expect(listing).to.be.a('array'); - - const notificationObj = mockNotification.get(); + const notificationObj = get(); expect(notificationObj.serviceName).to.equal('neubauKompass'); - notificationObj.payload.forEach((notify) => { expect(notify).to.be.a('object'); - /** check the actual structure **/ expect(notify.id).to.be.a('string'); expect(notify.title).to.be.a('string'); expect(notify.link).to.be.a('string'); expect(notify.address).to.be.a('string'); - /** check the values if possible **/ expect(notify.title).to.be.not.empty; expect(notify.link).that.does.include('https://www.neubaukompass.de'); diff --git a/test/provider/utils.test.js b/test/provider/utils.test.js index 0884ef3..68614f2 100644 --- a/test/provider/utils.test.js +++ b/test/provider/utils.test.js @@ -1,14 +1,13 @@ -const utils = require('../../lib/utils'); -const assert = require('assert'); -const expect = require('chai').expect; - +import utils from '../../lib/utils.js'; +import assert from 'assert'; +import chai from 'chai'; +const expect = chai.expect; const fakeWorkingHoursConfig = (from, to) => ({ workingHours: { to, from, }, }); - describe('utils', () => { describe('#isOneOf()', () => { it('should be false', () => { @@ -18,7 +17,6 @@ describe('utils', () => { assert.equal(utils.isOneOf('bla blub blubber', ['bla']), true); }); }); - describe('#duringWorkingHoursOrNotSet()', () => { it('should be false', () => { expect(utils.duringWorkingHoursOrNotSet(fakeWorkingHoursConfig('12:00', '13:00'), 0)).to.be.false; diff --git a/test/provider/wgGesucht.test.js b/test/provider/wgGesucht.test.js index cddb52f..0cc6ebf 100644 --- a/test/provider/wgGesucht.test.js +++ b/test/provider/wgGesucht.test.js @@ -1,35 +1,25 @@ -const similarityCache = require('../../lib/services/similarity-check/similarityCache'); -const mockNotification = require('../mocks/mockNotification'); -const providerConfig = require('./testProvider.json'); -const mockStore = require('../mocks/mockStore'); -const proxyquire = require('proxyquire').noCallThru(); -const expect = require('chai').expect; -const provider = require('../../lib/provider/wgGesucht'); - +import * as similarityCache from '../../lib/services/similarity-check/similarityCache.js'; +import { get } from '../mocks/mockNotification.js'; +import { mockFredy, providerConfig } from '../utils.js'; +import chai from 'chai'; +import * as provider from '../../lib/provider/wgGesucht.js'; +const expect = chai.expect; describe('#wgGesucht testsuite()', () => { after(() => { similarityCache.stopCacheCleanup(); }); provider.init(providerConfig.wgGesucht, [], []); - const Fredy = proxyquire('../../lib/FredyRuntime', { - './services/storage/listingsStorage': { - ...mockStore, - }, - './notification/notify': mockNotification, - }); - it('should test wgGesucht provider', async () => { + const Fredy = await mockFredy(); return await new Promise((resolve) => { const fredy = new Fredy(provider.config, null, provider.metaInformation.id, 'wgGesucht', similarityCache); fredy.execute().then((listing) => { expect(listing).to.be.a('array'); - const notificationObj = mockNotification.get(); + const notificationObj = get(); expect(notificationObj.serviceName).to.equal('wgGesucht'); notificationObj.payload.forEach((notify) => { expect(notify).to.be.a('object'); - /** check the actual structure **/ - expect(notify.id).to.be.a('string'); expect(notify.title).to.be.a('string'); expect(notify.details).to.be.a('string'); diff --git a/test/queryStringMutator/queryStringMutator.test.js b/test/queryStringMutator/queryStringMutator.test.js index 2ad419a..af155bc 100644 --- a/test/queryStringMutator/queryStringMutator.test.js +++ b/test/queryStringMutator/queryStringMutator.test.js @@ -1,9 +1,17 @@ -const testData = require('./testData.json'); -const expect = require('chai').expect; -const fs = require('fs'); +import fs from 'fs'; +import chai from 'chai'; +import { readFile } from 'fs/promises'; +import mutator from '../../lib/services/queryStringMutator.js'; +import queryString from 'query-string'; +const expect = chai.expect; -const mutator = require('../../lib/services/queryStringMutator.js'); -const queryString = require('query-string'); +const data = await readFile(new URL('./testData.json', import.meta.url)); + +const testData = JSON.parse(data); + +let _provider = await Promise.all( + fs.readdirSync('./lib/provider/').map(async (integPath) => await import(`../../lib/provider/${integPath}`)) +); /** * Test test might look a bit weird at first, but listen stranger... @@ -12,18 +20,14 @@ const queryString = require('query-string'); */ describe('queryStringMutator', () => { it('should fix all urls', () => { - let _provider = fs.readdirSync('./lib/provider/').map((integPath) => require(`../../lib/provider/${integPath}`)); - for (let test of testData) { const provider = _provider.find((p) => p.metaInformation.id === test.id); if (provider == null) { throw new Error(`Cannot find provider for given id: ${test.id}`); } - const fixedUrl = mutator(test.url, provider.config.sortByDateParam); const expectedParams = queryString.parseUrl(test.shouldBecome); const actualParams = queryString.parseUrl(fixedUrl); - //check if all new params are existing expect(Object.keys(expectedParams.query)).to.include.members(Object.keys(actualParams.query)); expect(Object.values(expectedParams.query)).to.include.members(Object.values(actualParams.query)); diff --git a/test/similarity/similarity.test.js b/test/similarity/similarity.test.js index 673b33d..5948b95 100644 --- a/test/similarity/similarity.test.js +++ b/test/similarity/similarity.test.js @@ -1,6 +1,6 @@ -const SimilarityCacheEntry = require('../../lib/services/similarity-check/SimilarityCacheEntry'); -const expect = require('chai').expect; - +import SimilarityCacheEntry from '../../lib/services/similarity-check/SimilarityCacheEntry.js'; +import chai from 'chai'; +const expect = chai.expect; describe('similarityCheck', () => { describe('#similarityCheck()', () => { it('should be false', () => { diff --git a/test/utils.js b/test/utils.js new file mode 100644 index 0000000..bf5ab73 --- /dev/null +++ b/test/utils.js @@ -0,0 +1,17 @@ +import { readFile } from 'fs/promises'; +import esmock from 'esmock'; +import * as mockStore from './mocks/mockStore.js'; +import { send } from './mocks/mockNotification.js'; + +export const providerConfig = JSON.parse(await readFile(new URL('./provider/testProvider.json', import.meta.url))); + +export const mockFredy = async () => { + return await esmock('../lib/FredyRuntime', { + '../lib/services/storage/listingsStorage.js': { + ...mockStore, + }, + '../lib/notification/notify.js': { + send, + }, + }); +}; diff --git a/ui/src/services/rematch/models/generalSettings.js b/ui/src/services/rematch/models/generalSettings.js index 6fc9a8b..5b3ef63 100644 --- a/ui/src/services/rematch/models/generalSettings.js +++ b/ui/src/services/rematch/models/generalSettings.js @@ -1,5 +1,4 @@ import { xhrGet } from '../../xhr'; - export const generalSettings = { state: { settings: {}, diff --git a/ui/src/services/rematch/models/jobs.js b/ui/src/services/rematch/models/jobs.js index 0e047ed..bc3deed 100644 --- a/ui/src/services/rematch/models/jobs.js +++ b/ui/src/services/rematch/models/jobs.js @@ -1,5 +1,4 @@ import { xhrGet } from '../../xhr'; - export const jobs = { state: { jobs: [], diff --git a/ui/src/services/rematch/models/user.js b/ui/src/services/rematch/models/user.js index 5db65a9..b23c333 100644 --- a/ui/src/services/rematch/models/user.js +++ b/ui/src/services/rematch/models/user.js @@ -1,5 +1,4 @@ import { xhrGet } from '../../xhr'; - export const user = { state: { users: [], diff --git a/ui/src/services/rematch/store.js b/ui/src/services/rematch/store.js index 0501dc2..e364979 100644 --- a/ui/src/services/rematch/store.js +++ b/ui/src/services/rematch/store.js @@ -6,14 +6,11 @@ import { createLogger } from 'redux-logger'; import { jobs } from './models/jobs'; import { user } from './models/user'; import { init } from '@rematch/core'; - const middleware = []; - if (process.env.NODE_ENV === 'development') { // eslint-disable-line no-redeclare middleware.push(createLogger({ duration: false, collapsed: (getState, action, logEntry) => !logEntry.error })); } - const store = init({ name: 'fredy', models: { @@ -28,5 +25,4 @@ const store = init({ middlewares: middleware, }, }); - export const reduxStore = store; diff --git a/ui/src/services/time/timeService.js b/ui/src/services/time/timeService.js index de8c22f..5801d22 100644 --- a/ui/src/services/time/timeService.js +++ b/ui/src/services/time/timeService.js @@ -8,5 +8,4 @@ export function format(ts) { second: 'numeric', }).format(ts); } - export const roundToNext5Minute = (ts) => Math.ceil(ts / (1000 * 60 * 5)) * (1000 * 60 * 5); diff --git a/ui/src/services/transformer/notificationAdapterTransformer.js b/ui/src/services/transformer/notificationAdapterTransformer.js index 8616443..b12cb76 100644 --- a/ui/src/services/transformer/notificationAdapterTransformer.js +++ b/ui/src/services/transformer/notificationAdapterTransformer.js @@ -1,10 +1,8 @@ export function transform({ id, name, fields }) { const fieldValues = {}; - Object.keys(fields).map((key) => { fieldValues[key] = fields[key].value; }); - return { id, name, diff --git a/ui/src/services/xhr.js b/ui/src/services/xhr.js index b11cf6e..a494b6c 100644 --- a/ui/src/services/xhr.js +++ b/ui/src/services/xhr.js @@ -9,7 +9,6 @@ export function xhrPost(url, data, contentType = 'application/json; charset=utf-8', isJson = true) { return executePostOrPutCall(url, contentType, data, isJson, true); } - /** * put request to backend. * @@ -21,7 +20,6 @@ export function xhrPost(url, data, contentType = 'application/json; charset=utf- export function xhrPut(url, data, contentType = 'application/json; charset=utf-8', isJson = true) { return executePostOrPutCall(url, contentType, data, isJson, false); } - function executePostOrPutCall(url, contentType, data, isJson, isPost) { return new Promise((resolve, reject) => { fetch(url, { @@ -41,7 +39,6 @@ function executePostOrPutCall(url, contentType, data, isJson, isPost) { }); }); } - /** * get request to backend * returns a Promise with @@ -75,7 +72,6 @@ export function xhrGet(url, contentType = 'application/json; charset=utf-8', isJ }); }); } - /** * delete request to backend * returns a Promise with @@ -114,7 +110,6 @@ export function xhrDelete(url, data, contentType = 'application/json; charset=ut }); }); } - function parseJSON(response) { return new Promise((resolve, reject) => response @@ -122,7 +117,6 @@ function parseJSON(response) { .then((text) => { //some responses doesn't contain a body. .json() would throw errors here... const json = text != null && text.length > 0 ? JSON.parse(text) : {}; - if (response.ok) { resolve({ status: response.status, diff --git a/vite.config.js b/vite.config.js index 7927175..baf8cc9 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,6 +1,5 @@ import react from '@vitejs/plugin-react'; import { defineConfig } from 'vite'; - // https://vitejs.dev/config/ export default defineConfig({ base: '', diff --git a/yarn.lock b/yarn.lock index d6acc69..8ff9d86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18,6 +18,14 @@ dependencies: "@jridgewell/trace-mapping" "^0.3.0" +"@ampproject/remapping@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + "@babel/code-frame@^7.0.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" @@ -42,7 +50,28 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.14.tgz#4106fc8b755f3e3ee0a0a7c27dde5de1d2b2baf8" integrity sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw== -"@babel/core@7.20.12", "@babel/core@^7.20.12": +"@babel/core@7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.0.tgz#1341aefdcc14ccc7553fcc688dd8986a2daffc13" + integrity sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.21.0" + "@babel/helper-compilation-targets" "^7.20.7" + "@babel/helper-module-transforms" "^7.21.0" + "@babel/helpers" "^7.21.0" + "@babel/parser" "^7.21.0" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.0" + "@babel/types" "^7.21.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.0" + +"@babel/core@^7.20.12": version "7.20.12" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.12.tgz#7930db57443c6714ad216953d1356dac0eb8496d" integrity sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg== @@ -63,7 +92,7 @@ json5 "^2.2.2" semver "^6.3.0" -"@babel/eslint-parser@^7.19.1": +"@babel/eslint-parser@7.19.1": version "7.19.1" resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz#4f68f6b0825489e00a24b41b6a1ae35414ecd2f4" integrity sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ== @@ -90,6 +119,16 @@ "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" +"@babel/generator@^7.21.0", "@babel/generator@^7.21.1": + version "7.21.1" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.1.tgz#951cc626057bc0af2c35cd23e9c64d384dea83dd" + integrity sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA== + dependencies: + "@babel/types" "^7.21.0" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + "@babel/helper-annotate-as-pure@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" @@ -179,6 +218,14 @@ "@babel/template" "^7.18.10" "@babel/types" "^7.19.0" +"@babel/helper-function-name@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4" + integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg== + dependencies: + "@babel/template" "^7.20.7" + "@babel/types" "^7.21.0" + "@babel/helper-hoist-variables@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" @@ -228,6 +275,20 @@ "@babel/traverse" "^7.20.10" "@babel/types" "^7.20.7" +"@babel/helper-module-transforms@^7.21.0": + version "7.21.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz#160caafa4978ac8c00ac66636cb0fa37b024e2d2" + integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.20.2" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.19.1" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.2" + "@babel/types" "^7.21.2" + "@babel/helper-optimise-call-expression@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" @@ -316,6 +377,15 @@ "@babel/traverse" "^7.20.13" "@babel/types" "^7.20.7" +"@babel/helpers@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.21.0.tgz#9dd184fb5599862037917cdc9eecb84577dc4e7e" + integrity sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA== + dependencies: + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.0" + "@babel/types" "^7.21.0" + "@babel/highlight@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" @@ -344,6 +414,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.15.tgz#eec9f36d8eaf0948bb88c87a46784b5ee9fd0c89" integrity sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg== +"@babel/parser@^7.21.0", "@babel/parser@^7.21.2": + version "7.21.2" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3" + integrity sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ== + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2" @@ -1080,6 +1155,22 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2": + version "7.21.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.2.tgz#ac7e1f27658750892e815e60ae90f382a46d8e75" + integrity sha512-ts5FFU/dSUPS13tv8XiEObDu9K+iagEKME9kAbaP7r0Y9KtZJZ+NGndDvWoRAYNpeWafbpFeki3q9QoMD6gxyw== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.21.1" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.21.0" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.21.2" + "@babel/types" "^7.21.2" + debug "^4.1.0" + globals "^11.1.0" + "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.4.4": version "7.20.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.5.tgz#e206ae370b5393d94dfd1d04cd687cace53efa84" @@ -1098,6 +1189,15 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" +"@babel/types@^7.21.0", "@babel/types@^7.21.2": + version "7.21.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.2.tgz#92246f6e00f91755893c2876ad653db70c8310d1" + integrity sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw== + dependencies: + "@babel/helper-string-parser" "^7.19.4" + "@babel/helper-validator-identifier" "^7.19.1" + to-fast-properties "^2.0.0" + "@esbuild/android-arm64@0.16.17": version "0.16.17" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz#cf91e86df127aa3d141744edafcba0abdc577d23" @@ -1208,14 +1308,26 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz#c5a1a4bfe1b57f0c3e61b29883525c6da3e5c091" integrity sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q== -"@eslint/eslintrc@^1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz#af58772019a2d271b7e2d4c23ff4ddcba3ccfb3e" - integrity sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA== +"@eslint-community/eslint-utils@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz#a831e6e468b4b2b5ae42bf658bea015bf10bc518" + integrity sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.4.0.tgz#3e61c564fcd6b921cb789838631c5ee44df09403" + integrity sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ== + +"@eslint/eslintrc@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.1.tgz#7888fe7ec8f21bc26d646dbd2c11cd776e21192d" + integrity sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.4.0" + espree "^9.5.0" globals "^13.19.0" ignore "^5.2.0" import-fresh "^3.2.1" @@ -1223,6 +1335,11 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@eslint/js@8.36.0": + version "8.36.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.36.0.tgz#9837f768c03a1e4a30bd304a64fb8844f0e72efe" + integrity sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg== + "@fluentui/react-component-event-listener@~0.63.0": version "0.63.1" resolved "https://registry.yarnpkg.com/@fluentui/react-component-event-listener/-/react-component-event-listener-0.63.1.tgz#c2af94893671f1d6bfe2a8a07dcfa2cb01b85f52" @@ -1257,6 +1374,14 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/gen-mapping@^0.3.2": version "0.3.2" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" @@ -1276,7 +1401,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== -"@jridgewell/set-array@^1.0.1": +"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== @@ -1299,7 +1424,7 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.9": +"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": version "0.3.17" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== @@ -1381,11 +1506,6 @@ "@sendgrid/client" "^7.7.0" "@sendgrid/helpers" "^7.7.0" -"@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" @@ -1457,28 +1577,11 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn-walk@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - -acorn@^8.7.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" - integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== - acorn@^8.8.0: version "8.8.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73" integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA== -agent-base@6, agent-base@^6.0.0: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - aggregate-error@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0" @@ -1608,11 +1711,6 @@ array.prototype.tosorted@^1.1.1: es-shim-unscopables "^1.0.0" get-intrinsic "^1.1.3" -asap@^2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= - assert@^1.3.0: version "1.5.0" resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" @@ -1626,13 +1724,6 @@ assertion-error@^1.1.0: resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== -ast-types@^0.13.2: - version "0.13.4" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" - integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w== - dependencies: - tslib "^2.0.1" - astral-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" @@ -1650,6 +1741,14 @@ axios@^0.26.0: dependencies: follow-redirects "^1.14.8" +axios@^0.27.2: + version "0.27.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + babel-plugin-polyfill-corejs2@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz#5d1bd3836d0a19e1b84bbf2d9640ccb6f951c122" @@ -1689,10 +1788,10 @@ batch@~0.6.0: resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= -better-sqlite3@8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-8.1.0.tgz#a0039c5dfdc04b733cac3c8dbe1b71f3e5fc62d3" - integrity sha512-p1m09H+Oi8R9TPj810pdNswMFuVgRNgCJEWypp6jlkOgSwMIrNyuj3hW78xEuBRGok5RzeaUW8aBtTWF3l/TQA== +better-sqlite3@8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-8.2.0.tgz#4ef6185b88992723de7e00cfa67585ac59f320bd" + integrity sha512-8eTzxGk9535SB3oSNu0tQ6I4ZffjVCBUjKHN9QeeIFtphBX0sEd0NxAuglBNR9TO5ThnxBB7GqzfcYo9kjadJQ== dependencies: bindings "^1.5.0" prebuild-install "^7.1.0" @@ -1728,13 +1827,13 @@ bluebird@^3.4.7: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -body-parser@1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" - integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== +body-parser@1.20.2: + version "1.20.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== dependencies: bytes "3.1.2" - content-type "~1.0.4" + content-type "~1.0.5" debug "2.6.9" depd "2.0.0" destroy "1.2.0" @@ -1742,7 +1841,7 @@ body-parser@1.20.1: iconv-lite "0.4.24" on-finished "2.4.1" qs "6.11.0" - raw-body "2.5.1" + raw-body "2.5.2" type-is "~1.6.18" unpipe "1.0.0" @@ -1796,11 +1895,6 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" -bytes@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== - bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -1842,6 +1936,11 @@ chai@4.3.7: pathval "^1.1.1" type-detect "^4.0.5" +chalk@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3" + integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== + chalk@^2.0.0, chalk@~2.4.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -2002,17 +2101,17 @@ combined-stream@^1.0.6, combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -commander@^9.4.1: - version "9.4.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.1.tgz#d1dd8f2ce6faf93147295c0df13c7c21141cfbdd" - integrity sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw== +commander@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.0.tgz#71797971162cd3cf65f0b9d24eb28f8d303acdf1" + integrity sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA== compare-versions@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== -component-emitter@^1.2.0, component-emitter@^1.3.0: +component-emitter@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== @@ -2029,11 +2128,16 @@ content-disposition@^0.5.0: dependencies: safe-buffer "5.1.2" -content-type@^1.0.1, content-type@~1.0.4: +content-type@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== +content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + convert-source-map@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" @@ -2056,11 +2160,6 @@ cookiejar@^2.1.0: resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== -cookiejar@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.3.tgz#fc7a6216e408e74414b90230050842dacda75acc" - integrity sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ== - cookies@0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.8.0.tgz#1293ce4b391740a8406e3c9870e828c4b54f3f90" @@ -2137,10 +2236,10 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.7.tgz#2a5fb75e1015e84dd15692f71e89a1450290950b" integrity sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g== -data-uri-to-buffer@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" - integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og== +data-uri-to-buffer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" + integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== debug@2.6.9, debug@^2.1.3: version "2.6.9" @@ -2156,13 +2255,6 @@ debug@3.2.7, debug@^3.2.6: dependencies: ms "^2.1.1" -debug@4: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== - dependencies: - ms "2.1.2" - debug@4.3.4, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" @@ -2196,10 +2288,10 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== -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== +decode-uri-component@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.4.1.tgz#2ac4859663c704be22bf7db760a1494a49ab2cc5" + integrity sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ== decompress-response@^6.0.0: version "6.0.0" @@ -2225,7 +2317,7 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deep-is@^0.1.3, deep-is@~0.1.3: +deep-is@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= @@ -2250,16 +2342,6 @@ define-properties@^1.1.4: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -degenerator@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-3.0.2.tgz#6a61fcc42a702d6e50ff6023fe17bff435f68235" - integrity sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ== - dependencies: - ast-types "^0.13.2" - escodegen "^1.8.1" - esprima "^4.0.0" - vm2 "^3.9.8" - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -2275,11 +2357,6 @@ depd@2.0.0, depd@~2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - destroy@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" @@ -2295,14 +2372,6 @@ detect-libc@^2.0.0: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.0.tgz#c528bc09bc6d1aa30149228240917c225448f204" integrity sha512-S55LzUl8HUav8l9E2PBTlC5PAJrHK7tkM+XXFGD+fbsbkTzhCpG6K05LxJcUOEWzMa4v6ptcMZ9s3fOdJDu0Zw== -dezalgo@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" - integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= - dependencies: - asap "^2.0.0" - wrappy "1" - diff@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" @@ -2607,22 +2676,10 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -escodegen@^1.8.1: - version "1.14.3" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" - integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== - dependencies: - esprima "^4.0.1" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - -eslint-config-prettier@8.6.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz#dec1d29ab728f4fa63061774e1672ac4e363d207" - integrity sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA== +eslint-config-prettier@8.7.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.7.0.tgz#f1cc58a8afebc50980bd53475451df146c13182d" + integrity sha512-HHVXLSlVUhMSmyW4ZzEuvjpwqamgmlfkutD53cYXLikh4pt/modINRcCIApJ84czDxM4GZInwUrromsDdTImTA== eslint-plugin-react@7.32.2: version "7.32.2" @@ -2661,18 +2718,6 @@ eslint-scope@^7.1.1: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" - integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== - eslint-visitor-keys@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" @@ -2683,12 +2728,15 @@ eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@8.34.0: - version "8.34.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.34.0.tgz#fe0ab0ef478104c1f9ebc5537e303d25a8fb22d6" - integrity sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg== +eslint@8.36.0: + version "8.36.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.36.0.tgz#1bd72202200a5492f91803b113fb8a83b11285cf" + integrity sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw== dependencies: - "@eslint/eslintrc" "^1.4.1" + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.4.0" + "@eslint/eslintrc" "^2.0.1" + "@eslint/js" "8.36.0" "@humanwhocodes/config-array" "^0.11.8" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" @@ -2699,10 +2747,9 @@ eslint@8.34.0: doctrine "^3.0.0" escape-string-regexp "^4.0.0" eslint-scope "^7.1.1" - eslint-utils "^3.0.0" eslint-visitor-keys "^3.3.0" - espree "^9.4.0" - esquery "^1.4.0" + espree "^9.5.0" + esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" @@ -2723,29 +2770,28 @@ eslint@8.34.0: minimatch "^3.1.2" natural-compare "^1.4.0" optionator "^0.9.1" - regexpp "^3.2.0" strip-ansi "^6.0.1" strip-json-comments "^3.1.0" text-table "^0.2.0" -espree@^9.4.0: - version "9.4.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd" - integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg== +esmock@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/esmock/-/esmock-2.1.0.tgz#20fbff7f9096cff8c28560eedaca791ca22d6eb0" + integrity sha512-8/2+iFfcB5FMJDBWXmXCY/4GSaI8sMCWUmq2laroQc3y9AI53QMm5Ew25DkW9FMaM8dBH8hmvOr2l3qChJ2JgA== + +espree@^9.5.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.0.tgz#3646d4e3f58907464edba852fa047e6a27bdf113" + integrity sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw== dependencies: acorn "^8.8.0" acorn-jsx "^5.3.2" eslint-visitor-keys "^3.3.0" -esprima@^4.0.0, esprima@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== dependencies: estraverse "^5.1.0" @@ -2756,7 +2802,7 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.1.1: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -2786,14 +2832,14 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -execa@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-6.1.0.tgz#cea16dee211ff011246556388effa0818394fb20" - integrity sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA== +execa@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-7.1.0.tgz#50c6f39438b7ce407e8c7a6829c72b074778238d" + integrity sha512-T6nIJO3LHxUZ6ahVRaxXz9WLEruXLqdcluA+UuTptXmLM7nDAn9lx9IfkxPyzEL21583qSt4RmL44pO71EHaJQ== dependencies: cross-spawn "^7.0.3" get-stream "^6.0.1" - human-signals "^3.0.1" + human-signals "^4.3.0" is-stream "^3.0.0" merge-stream "^2.0.0" npm-run-path "^5.1.0" @@ -2831,16 +2877,11 @@ fast-json-stable-stringify@^2.0.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-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: +fast-levenshtein@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= -fast-safe-stringify@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" - integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== - fastq@^1.6.0: version "1.8.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481" @@ -2848,6 +2889,14 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fetch-blob@^3.1.2, fetch-blob@^3.1.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" + integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== + dependencies: + node-domexception "^1.0.0" + web-streams-polyfill "^3.0.3" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -2860,19 +2909,6 @@ file-uri-to-path@1.0.0: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== -file-uri-to-path@2: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz#7b415aeba227d575851e0a5b0c640d7656403fba" - integrity sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg== - -fill-keys@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/fill-keys/-/fill-keys-1.0.2.tgz#9a8fa36f4e8ad634e3bf6b4f3c8882551452eb20" - integrity sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA= - dependencies: - is-object "~1.0.1" - merge-descriptors "~1.0.0" - fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -2880,10 +2916,10 @@ 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 sha1-mzERErxsYSehbgFsbF1/GeCAXFs= +filter-obj@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-5.1.0.tgz#5bd89676000a713d7db2e197f660274428e524ed" + integrity sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng== find-up@5.0.0, find-up@^5.0.0: version "5.0.0" @@ -2923,6 +2959,11 @@ follow-redirects@^1.14.8: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== +follow-redirects@^1.14.9: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + form-data@^2.3.1: version "2.5.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" @@ -2946,21 +2987,18 @@ format-parser@0.0.2: resolved "https://registry.yarnpkg.com/format-parser/-/format-parser-0.0.2.tgz#4318822a8a9f1a29a0137253b908719c4f9222a2" integrity sha1-QxiCKoqfGimgE3JTuQhxnE+SIqI= +formdata-polyfill@^4.0.10: + version "4.0.10" + resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" + integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== + dependencies: + fetch-blob "^3.1.2" + formidable@^1.2.0: version "1.2.2" resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.2.tgz#bf69aea2972982675f00865342b982986f6b8dd9" integrity sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q== -formidable@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/formidable/-/formidable-2.0.1.tgz#4310bc7965d185536f9565184dee74fbb75557ff" - integrity sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ== - dependencies: - dezalgo "1.0.3" - hexoid "1.0.0" - once "1.4.0" - qs "6.9.3" - fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" @@ -2971,15 +3009,6 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -2990,14 +3019,6 @@ fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== -ftp@^0.3.10: - version "0.3.10" - resolved "https://registry.yarnpkg.com/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d" - integrity sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0= - dependencies: - readable-stream "1.1.x" - xregexp "2.0.0" - function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -3064,18 +3085,6 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" -get-uri@3: - version "3.0.2" - resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c" - integrity sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg== - dependencies: - "@tootallnate/once" "1" - data-uri-to-buffer "3" - debug "4" - file-uri-to-path "2" - fs-extra "^8.1.0" - ftp "^0.3.10" - github-from-package@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" @@ -3143,16 +3152,6 @@ graceful-fs@^4.1.2: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== -graceful-fs@^4.1.3: - version "4.2.8" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" - integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== - -graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.6" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" - integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== - grapheme-splitter@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" @@ -3231,15 +3230,10 @@ he@1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -hexoid@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18" - integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g== - -highcharts-react-official@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/highcharts-react-official/-/highcharts-react-official-3.1.0.tgz#921e5614f9e8580bc99a1e3b531d51a70f396500" - integrity sha512-CkWJHrVMOc6CT8KFu1dR+a0w5OxCVKKgZUNWtEi5TmR0xqBDIDe+RyM652MAN/jBYppxMo6TCUVlRObCyWAn0Q== +highcharts-react-official@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/highcharts-react-official/-/highcharts-react-official-3.2.0.tgz#42f8f237d73eec6791318efb41237067000cf815" + integrity sha512-71IJZsLmEboYFjONpwC3NRsg6JKvtKYtS5Si3e6s6MLRSOFNOY8KILTkzvO36kjpeR/A0X3/kvvewE+GMPpkjw== highcharts@10.3.3: version "10.3.3" @@ -3308,17 +3302,6 @@ http-context@^1.1.0: type-is "^1.6.1" vary "^1.0.0" -http-errors@1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" - integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - http-errors@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" @@ -3340,27 +3323,10 @@ http-outgoing@^0.12.0: resolved "https://registry.yarnpkg.com/http-outgoing/-/http-outgoing-0.12.0.tgz#662f3a27c7a4d14c924b5f5314909efabde1830d" integrity sha1-Zi86J8ek0UySS19TFJCe+r3hgw0= -http-proxy-agent@^4.0.0, http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - -https-proxy-agent@5, https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== - dependencies: - agent-base "6" - debug "4" - -human-signals@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-3.0.1.tgz#c740920859dafa50e5a3222da9d3bf4bb0e5eef5" - integrity sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ== +human-signals@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.0.tgz#2095c3cd5afae40049403d4b811235b03879db50" + integrity sha512-zyzVyMjpGBX2+6cDVZeFPCdtOtdsxOeseRhB9tkQ6xXmGUNrcnBzdEKPy3VPNYz+4gy1oukVOXcrJCunSyc6QQ== husky@4.3.8: version "4.3.8" @@ -3433,7 +3399,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -3457,11 +3423,6 @@ internal-slot@^1.0.3: has "^1.0.3" side-channel "^1.0.4" -ip@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" - integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= - is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -3582,11 +3543,6 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-object@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" - integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= - is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" @@ -3597,11 +3553,6 @@ is-plain-obj@^2.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== -is-promise@^2.1.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" - integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== - is-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff" @@ -3763,13 +3714,6 @@ json5@^2.2.2: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - "jsx-ast-utils@^2.4.1 || ^3.0.0": version "3.1.0" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.1.0.tgz#642f1d7b88aa6d7eb9d8f2210e166478444fa891" @@ -3820,54 +3764,46 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -lilconfig@2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4" - integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg== +lilconfig@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== lines-and-columns@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= -lint-staged@13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.1.2.tgz#443636a0cfd834d5518d57d228130dc04c83d6fb" - integrity sha512-K9b4FPbWkpnupvK3WXZLbgu9pchUJ6N7TtVZjbaPsoizkqFUDkUReUL25xdrCljJs7uLUF3tZ7nVPeo/6lp+6w== +lint-staged@13.2.0: + version "13.2.0" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.2.0.tgz#b7abaf79c91cd36d824f17b23a4ce5209206126a" + integrity sha512-GbyK5iWinax5Dfw5obm2g2ccUiZXNGtAS4mCbJ0Lv4rq6iEtfBSjOYdcbOtAIFtM114t0vdpViDDetjVTSd8Vw== dependencies: + chalk "5.2.0" cli-truncate "^3.1.0" - colorette "^2.0.19" - commander "^9.4.1" + commander "^10.0.0" debug "^4.3.4" - execa "^6.1.0" - lilconfig "2.0.6" - listr2 "^5.0.5" + execa "^7.0.0" + lilconfig "2.1.0" + listr2 "^5.0.7" micromatch "^4.0.5" normalize-path "^3.0.0" - object-inspect "^1.12.2" + object-inspect "^1.12.3" pidtree "^0.6.0" string-argv "^0.3.1" - yaml "^2.1.3" + yaml "^2.2.1" -listr2@^5.0.5: - version "5.0.6" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-5.0.6.tgz#3c61153383869ffaad08a8908d63edfde481dff8" - integrity sha512-u60KxKBy1BR2uLJNTWNptzWQ1ob/gjMzIJPZffAENzpZqbMZ/5PrXXOomDcevIS/+IB7s1mmCEtSlT2qHWMqag== +listr2@^5.0.7: + version "5.0.8" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-5.0.8.tgz#a9379ffeb4bd83a68931a65fb223a11510d6ba23" + integrity sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA== dependencies: cli-truncate "^2.1.0" colorette "^2.0.19" log-update "^4.0.0" p-map "^4.0.0" rfdc "^1.3.0" - rxjs "^7.5.7" + rxjs "^7.8.0" through "^2.3.8" wrap-ansi "^7.0.0" @@ -3948,7 +3884,7 @@ lodash.some@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0= -lodash@4, lodash@^4.17.21: +lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -3985,16 +3921,12 @@ loupe@^2.3.1: dependencies: get-func-name "^2.0.0" -lowdb@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lowdb/-/lowdb-1.0.0.tgz#5243be6b22786ccce30e50c9a33eac36b20c8064" - integrity sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ== +lowdb@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/lowdb/-/lowdb-5.1.0.tgz#3d9f13522ea92e445348a7d455a69ce570c2f51d" + integrity sha512-OEysJ2S3j05RqehEypEv3h6EgdV4Y7LTq7LngRNqe1IxsInOm66/sa3fzoI6mmqs2CC+zIJW3vfncGNv2IGi3A== dependencies: - graceful-fs "^4.1.3" - is-promise "^2.1.0" - lodash "4" - pify "^3.0.0" - steno "^0.4.1" + steno "^3.0.0" lru-cache@^5.1.1: version "5.1.1" @@ -4042,17 +3974,12 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= -merge-descriptors@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= - merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -methods@^1.1.1, methods@^1.1.2: +methods@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= @@ -4082,11 +4009,6 @@ mime@1.6.0, mime@^1.4.1: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@^2.5.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" - integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== - mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -4168,11 +4090,6 @@ mocha@10.2.0: yargs-parser "20.2.4" yargs-unparser "2.0.0" -module-not-found-error@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/module-not-found-error/-/module-not-found-error-1.0.1.tgz#cf8b4ff4f29640674d6cdd02b0e3bc523c2bbdc0" - integrity sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA= - monotonic-timestamp@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/monotonic-timestamp/-/monotonic-timestamp-0.0.8.tgz#67987d02a41c15f568b6c0a05885989dd2402ba0" @@ -4198,6 +4115,11 @@ nanoid@3.3.3: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== +nanoid@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-4.0.1.tgz#398d7ccfdbf9faf2231b2ca7e8fff5dbca6a509b" + integrity sha512-udKGtCCUafD3nQtJg9wBhRP3KMbPglUsgV5JVsXhvyBs/oefqb4sqMEhKBBgqZncYowu58p1prsZQBYvAj/Gww== + nanoid@^3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" @@ -4232,11 +4154,6 @@ neo-async@^2.6.0: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -netmask@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" - integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== - node-abi@^3.3.0: version "3.8.0" resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.8.0.tgz#679957dc8e7aa47b0a02589dbfde4f77b29ccb32" @@ -4244,22 +4161,28 @@ node-abi@^3.3.0: dependencies: semver "^7.3.5" -node-fetch@2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" - integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== - dependencies: - whatwg-url "^5.0.0" +node-domexception@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== -node-mailjet@3.3.13: - version "3.3.13" - resolved "https://registry.yarnpkg.com/node-mailjet/-/node-mailjet-3.3.13.tgz#2fc38d76b3c6c1a9296d25102eedecb74346e203" - integrity sha512-NnbD/7vbw+VVmcWnM6AFEx+xoZmEXpT9Q20yy/WPgGjeV+IMQ/3/Op55ZpOowU/tbir/yIZ0qTVU3H0/KN4X/g== +node-fetch@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.1.tgz#b3eea7b54b3a48020e46f4f88b9c5a7430d20b2e" + integrity sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow== dependencies: + data-uri-to-buffer "^4.0.0" + fetch-blob "^3.1.4" + formdata-polyfill "^4.0.10" + +node-mailjet@6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/node-mailjet/-/node-mailjet-6.0.2.tgz#a427f675f555920ec0fdd4b8887ac93473791121" + integrity sha512-aLSWqzVVB7fSfEE9yFsWQ3mPOcGtKJYmQTcL6an+Y8ITLjF8RdvopXvENgSjLLfFNAaIJ0PhLgECxutbmR84wA== + dependencies: + axios "^0.27.2" json-bigint "^1.0.0" - qs "^6.5.0" - superagent "^7.1.1" - superagent-proxy "^3.0.0" + url-join "^4.0.0" node-releases@^2.0.6: version "2.0.6" @@ -4307,6 +4230,11 @@ object-inspect@^1.12.2: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== +object-inspect@^1.12.3: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + object-inspect@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" @@ -4421,7 +4349,7 @@ on-headers@~1.0.2: resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== -once@1.4.0, once@^1.3.0, once@^1.3.1, once@^1.4.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= @@ -4447,18 +4375,6 @@ opencollective-postinstall@^2.0.2: resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz#5657f1bede69b6e33a45939b061eb53d3c6c3a89" integrity sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw== -optionator@^0.8.1: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - optionator@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" @@ -4497,30 +4413,6 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -pac-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz#b718f76475a6a5415c2efbe256c1c971c84f635e" - integrity sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - get-uri "3" - http-proxy-agent "^4.0.1" - https-proxy-agent "5" - pac-resolver "^5.0.0" - raw-body "^2.2.0" - socks-proxy-agent "5" - -pac-resolver@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-5.0.0.tgz#1d717a127b3d7a9407a16d6e1b012b13b9ba8dc0" - integrity sha512-H+/A6KitiHNNW+bxBKREk2MCGSxljfqRX76NjummWEYIat7ldVXRU3dhRIE3iXZ0nvGBk6smv3nntxKkzRL8NA== - dependencies: - degenerator "^3.0.1" - ip "^1.1.5" - netmask "^2.0.1" - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -4568,11 +4460,6 @@ path-key@^4.0.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" @@ -4620,11 +4507,6 @@ pidtree@^0.6.0: resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - pify@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" @@ -4676,11 +4558,6 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - prettier@2.8.4: version "2.8.4" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3" @@ -4714,34 +4591,6 @@ prop-types@^15.8.1: object-assign "^4.1.1" react-is "^16.13.1" -proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-5.0.0.tgz#d31405c10d6e8431fde96cba7a0c027ce01d633b" - integrity sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g== - dependencies: - agent-base "^6.0.0" - debug "4" - http-proxy-agent "^4.0.0" - https-proxy-agent "^5.0.0" - lru-cache "^5.1.1" - pac-proxy-agent "^5.0.0" - proxy-from-env "^1.0.0" - socks-proxy-agent "^5.0.0" - -proxy-from-env@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - -proxyquire@2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/proxyquire/-/proxyquire-2.1.3.tgz#2049a7eefa10a9a953346a18e54aab2b4268df39" - integrity sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg== - dependencies: - fill-keys "^1.0.2" - module-not-found-error "^1.0.1" - resolve "^1.11.1" - prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -4767,37 +4616,19 @@ qs@6.11.0: dependencies: side-channel "^1.0.4" -qs@6.9.3: - version "6.9.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.3.tgz#bfadcd296c2d549f1dffa560619132c977f5008e" - integrity sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw== - -qs@^6.10.3: - version "6.10.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" - integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== - dependencies: - side-channel "^1.0.4" - -qs@^6.5.0: - version "6.9.4" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687" - integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ== - qs@^6.5.1: version "6.9.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.1.tgz#20082c65cb78223635ab1a9eaca8875a29bf8ec9" integrity sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA== -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== +query-string@8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-8.1.0.tgz#e7f95367737219544cd360a11a4f4ca03836e115" + integrity sha512-BFQeWxJOZxZGix7y+SByG3F36dA0AbTy9o6pSmKFcFz7DAj0re9Frkty3saBn3nHo3D0oZJ/+rx3r8H8r8Jbpw== dependencies: - decode-uri-component "^0.2.2" - filter-obj "^1.1.0" - split-on-first "^1.0.0" - strict-uri-encode "^2.0.0" + decode-uri-component "^0.4.1" + filter-obj "^5.1.0" + split-on-first "^3.0.0" querystring@^0.2.0: version "0.2.0" @@ -4816,26 +4647,16 @@ range-parser@~1.2.1: resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== -raw-body@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" - integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== dependencies: bytes "3.1.2" http-errors "2.0.0" iconv-lite "0.4.24" unpipe "1.0.0" -raw-body@^2.2.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c" - integrity sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA== - dependencies: - bytes "3.1.0" - http-errors "1.7.3" - iconv-lite "0.4.24" - unpipe "1.0.0" - rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -4942,16 +4763,6 @@ react@18.2.0: dependencies: loose-envify "^1.1.0" -readable-stream@1.1.x: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - readable-stream@^2.3.5: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" @@ -4965,7 +4776,7 @@ readable-stream@^2.3.5: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: +readable-stream@^3.1.1, readable-stream@^3.4.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -5048,11 +4859,6 @@ regexparam@^2.0.1: resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-2.0.1.tgz#c912f5dae371e3798100b3c9ce22b7414d0889fa" integrity sha512-zRgSaYemnNYxUv+/5SeoHI0eJIgTL/A2pUtXUPLHQxUldagouJ9p+K6IbIZ/JiQuCEv2E2B1O11SjVQy3aMCkw== -regexpp@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - regexpu-core@^5.2.1: version "5.2.2" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.2.2.tgz#3e4e5d12103b64748711c3aad69934d7718e75fc" @@ -5092,13 +4898,6 @@ resolve-pathname@^3.0.0: resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== -resolve@^1.11.1: - version "1.15.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" - integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== - dependencies: - path-parse "^1.0.6" - resolve@^1.14.2, resolve@^1.22.1: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" @@ -5161,7 +4960,7 @@ run-parallel@^1.1.9: resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== -rxjs@^7.5.7: +rxjs@^7.8.0: version "7.8.0" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4" integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg== @@ -5260,13 +5059,6 @@ semver@^7.3.5: dependencies: lru-cache "^6.0.0" -semver@^7.3.7: - version "7.3.7" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" - integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== - dependencies: - lru-cache "^6.0.0" - send@0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" @@ -5303,11 +5095,6 @@ serve-static@1.15.0: parseurl "~1.3.3" send "0.18.0" -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== - setprototypeof@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" @@ -5406,59 +5193,35 @@ sliced@0.0.5: resolved "https://registry.yarnpkg.com/sliced/-/sliced-0.0.5.tgz#5edc044ca4eb6f7816d50ba2fc63e25d8fe4707f" integrity sha1-XtwETKTrb3gW1Qui/GPiXY/kcH8= -smart-buffer@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.1.0.tgz#91605c25d91652f4661ea69ccf45f1b331ca21ba" - integrity sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw== - -socks-proxy-agent@5, socks-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz#7c0f364e7b1cf4a7a437e71253bed72e9004be60" - integrity sha512-lEpa1zsWCChxiynk+lCycKuC502RxDWLKJZoIhnxrWNjLSDGYRFflHA1/228VkRcnv9TIb8w98derGbpKxJRgA== - dependencies: - agent-base "6" - debug "4" - socks "^2.3.3" - -socks@^2.3.3: - version "2.6.1" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e" - integrity sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA== - dependencies: - ip "^1.1.5" - smart-buffer "^4.1.0" - source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== -source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: +source-map@^0.6.1, source-map@~0.6.0: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -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== +split-on-first@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-3.0.0.tgz#f04959c9ea8101b9b0bbf35a61b9ebea784a23e7" + integrity sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA== statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== -"statuses@>= 1.5.0 < 2", statuses@^1.2.1: +statuses@^1.2.1: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= -steno@^0.4.1: - version "0.4.4" - resolved "https://registry.yarnpkg.com/steno/-/steno-0.4.4.tgz#071105bdfc286e6615c0403c27e9d7b5dcb855cb" - integrity sha1-BxEFvfwobmYVwEA8J+nXtdy4Vcs= - dependencies: - graceful-fs "^4.1.3" +steno@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/steno/-/steno-3.0.0.tgz#212a11e8ef3646b610efc8953842f556fd0df28f" + integrity sha512-uZtn7Ht9yXLiYgOsmo8btj4+f7VxyYheMt8g6F1ANjyqByQXEE2Gygjgenp3otHH1TlHsS4JAaRGv5wJ1wvMNw== stream-to-string@^1.1.0: version "1.2.0" @@ -5467,11 +5230,6 @@ stream-to-string@^1.1.0: dependencies: promise-polyfill "^1.1.6" -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 sha1-ucczDHBChi9rFC3CdLvMWGbONUY= - string-argv@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" @@ -5571,11 +5329,6 @@ string_decoder@^1.1.1: 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" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -5624,14 +5377,6 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -superagent-proxy@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/superagent-proxy/-/superagent-proxy-3.0.0.tgz#e1a17ccba25883599e18d2974020fe83ee7d95d1" - integrity sha512-wAlRInOeDFyd9pyonrkJspdRAxdLrcsZ6aSnS+8+nu4x1aXbz6FWSTT9M6Ibze+eG60szlL7JA8wEIV7bPWuyQ== - dependencies: - debug "^4.3.2" - proxy-agent "^5.0.0" - superagent@^3.6.0: version "3.8.3" resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" @@ -5648,23 +5393,6 @@ superagent@^3.6.0: qs "^6.5.1" readable-stream "^2.3.5" -superagent@^7.1.1: - version "7.1.3" - resolved "https://registry.yarnpkg.com/superagent/-/superagent-7.1.3.tgz#783ff8330e7c2dad6ad8f0095edc772999273b6b" - integrity sha512-WA6et4nAvgBCS73lJvv1D0ssI5uk5Gh+TGN/kNe+B608EtcVs/yzfl+OLXTzDs7tOBDIpvgh/WUs1K2OK1zTeQ== - dependencies: - component-emitter "^1.3.0" - cookiejar "^2.1.3" - debug "^4.3.4" - fast-safe-stringify "^2.1.1" - form-data "^4.0.0" - formidable "^2.0.1" - methods "^1.1.2" - mime "^2.5.0" - qs "^6.10.3" - readable-stream "^3.6.0" - semver "^7.3.7" - supports-color@8.1.1: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" @@ -5749,21 +5477,11 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== - toidentifier@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - trouter@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/trouter/-/trouter-3.2.0.tgz#a9c510fce21b8e659a28732c9de9d82871efe8df" @@ -5771,11 +5489,6 @@ trouter@^3.2.0: dependencies: regexparam "^1.3.0" -tslib@^2.0.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" - integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== - tslib@^2.1.0, tslib@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" @@ -5800,13 +5513,6 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - type-detect@^4.0.0, type-detect@^4.0.5: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" @@ -5878,11 +5584,6 @@ unicode-property-aliases-ecmascript@^2.0.0: resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - unpipe@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -5903,6 +5604,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +url-join@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" + integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== + use-sync-external-store@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.1.0.tgz#3343c3fe7f7e404db70f8c687adf5c1652d34e82" @@ -5930,10 +5636,10 @@ vary@^1.0.0: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= -vite@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/vite/-/vite-4.1.1.tgz#3b18b81a4e85ce3df5cbdbf4c687d93ebf402e6b" - integrity sha512-LM9WWea8vsxhr782r9ntg+bhSFS06FJgCvvB0+8hf8UWtvaiDagKYWXndjfX6kGl74keHJUcpzrQliDXZlF5yg== +vite@4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/vite/-/vite-4.1.4.tgz#170d93bcff97e0ebc09764c053eebe130bfe6ca0" + integrity sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg== dependencies: esbuild "^0.16.14" postcss "^8.4.21" @@ -5942,14 +5648,6 @@ vite@4.1.1: optionalDependencies: fsevents "~2.3.2" -vm2@^3.9.8: - version "3.9.9" - resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.9.tgz#c0507bc5fbb99388fad837d228badaaeb499ddc5" - integrity sha512-xwTm7NLh/uOjARRBs8/95H0e8fT3Ukw5D/JJWhxMbhKzNh1Nu981jQKvkep9iKYNxzlVrdzD0mlBGkDKZWprlw== - dependencies: - acorn "^8.7.0" - acorn-walk "^8.2.0" - warning@^4.0.2: version "4.0.3" resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" @@ -5957,18 +5655,10 @@ warning@^4.0.2: dependencies: loose-envify "^1.0.0" -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" +web-streams-polyfill@^3.0.3: + version "3.2.1" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" + integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== which-boxed-primitive@^1.0.2: version "1.0.2" @@ -5993,7 +5683,7 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -word-wrap@^1.2.3, word-wrap@~1.2.3: +word-wrap@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== @@ -6082,11 +5772,6 @@ x-ray@2.3.4: x-ray-crawler "~2.0.1" x-ray-parse "~1.0.1" -xregexp@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" - integrity sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM= - y18n@^5.0.5: version "5.0.5" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.5.tgz#8769ec08d03b1ea2df2500acef561743bbb9ab18" @@ -6107,10 +5792,10 @@ yaml@^1.10.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e" integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg== -yaml@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.3.tgz#9b3a4c8aff9821b696275c79a8bee8399d945207" - integrity sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg== +yaml@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.2.1.tgz#3014bf0482dcd15147aa8e56109ce8632cd60ce4" + integrity sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw== yargs-parser@20.2.4: version "20.2.4"