diff --git a/packages/rest-api/.eslintrc.js b/packages/rest-api/.eslintrc.js index a97c7be3f2..98e4e24b83 100644 --- a/packages/rest-api/.eslintrc.js +++ b/packages/rest-api/.eslintrc.js @@ -12,6 +12,8 @@ module.exports = { rules: { 'guard-for-in': 'off', 'jsdoc/check-indentation': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-unused-vars': 'off', }, }, ], diff --git a/packages/rest-api/package.json b/packages/rest-api/package.json index fa41f97411..876f4ebb64 100644 --- a/packages/rest-api/package.json +++ b/packages/rest-api/package.json @@ -30,7 +30,8 @@ "jest": "^29.7.0", "lodash": "^4.17.21", "supertest": "^6.3.3", - "typescript": "^4.8.3" + "typescript": "^4.8.3", + "winston": "^3.14.2" }, "description": "A node.js project exposing a rest api for synapse sdk quotes", "devDependencies": { diff --git a/packages/rest-api/src/app.ts b/packages/rest-api/src/app.ts index a6cecc6fb3..3921bb06c0 100644 --- a/packages/rest-api/src/app.ts +++ b/packages/rest-api/src/app.ts @@ -3,12 +3,44 @@ import swaggerUi from 'swagger-ui-express' import { specs } from './swagger' import routes from './routes' +import { logger } from './middleware/logger' const app = express() const port = process.env.PORT || 3000 app.use(express.json()) +app.use((req, res, next) => { + logger.info('Incoming request', { + method: req.method, + path: req.path, + query: req.query, + body: req.method === 'POST' || req.method === 'PUT' ? req.body : undefined, + }) + + const originalPath = req.path + + const originalJson = res.json + res.json = function (body) { + logger.info('Outgoing response', { + method: req.method, + path: originalPath, + statusCode: res.statusCode, + body: + originalPath === '/' || originalPath.toLowerCase() === '/tokenlist' + ? '[truncated for size]' + : body, + }) + return originalJson.call(this, body) + } + + next() +}) + +app.listen(port, () => { + logger.info(`Server is listening on port ${port}`) +}) + app.use( '/api-docs', (_req, res, next) => { @@ -27,6 +59,16 @@ app.use( app.use('/', routes) -export const server = app.listen(port, () => { - console.log(`Server listening at ${port}`) +app.use((err, _req, res, _next) => { + logger.error(`Express error: ${err.message}`, { stack: err.stack }) + res.status(500).json({ error: 'Something went wrong', details: err.message }) +}) + +process.on('uncaughtException', (err) => { + logger.error(`Uncaught Exception: ${err.message}`, { stack: err.stack }) + process.exit(1) +}) + +process.on('unhandledRejection', (reason, promise) => { + logger.error('Unhandled Rejection at:', promise, 'reason:', reason) }) diff --git a/packages/rest-api/src/controllers/bridgeController.ts b/packages/rest-api/src/controllers/bridgeController.ts index f69c8715f0..93e55537a7 100644 --- a/packages/rest-api/src/controllers/bridgeController.ts +++ b/packages/rest-api/src/controllers/bridgeController.ts @@ -4,6 +4,7 @@ import { parseUnits } from '@ethersproject/units' import { formatBNToString } from '../utils/formatBNToString' import { Synapse } from '../services/synapseService' import { tokenAddressToToken } from '../utils/tokenAddressToToken' +import { logger } from '../middleware/logger' export const bridgeController = async (req, res) => { const errors = validationResult(req) @@ -53,8 +54,18 @@ export const bridgeController = async (req, res) => { ), } }) + + logger.info(`Successful bridgeController response`, { + payload, + query: req.query, + }) res.json(payload) } catch (err) { + logger.error(`Error in bridgeController`, { + query: req.query, + error: err.message, + stack: err.stack, + }) res.status(500).json({ error: 'An unexpected error occurred in /bridge. Please try again later.', details: err.message, diff --git a/packages/rest-api/src/controllers/bridgeLimitsController.ts b/packages/rest-api/src/controllers/bridgeLimitsController.ts index 1ef292338f..03ddbb48e3 100644 --- a/packages/rest-api/src/controllers/bridgeLimitsController.ts +++ b/packages/rest-api/src/controllers/bridgeLimitsController.ts @@ -5,6 +5,7 @@ import { parseUnits } from '@ethersproject/units' import { Synapse } from '../services/synapseService' import { tokenAddressToToken } from '../utils/tokenAddressToToken' import { formatBNToString } from '../utils/formatBNToString' +import { logger } from '../middleware/logger' export const bridgeLimitsController = async (req, res) => { const errors = validationResult(req) @@ -94,11 +95,22 @@ export const bridgeLimitsController = async (req, res) => { minAmountOriginQueryTokenOutInfo.decimals ) - return res.json({ + const payload = { maxOriginAmount, minOriginAmount, + } + + logger.info(`Succesful bridgeLimitsController response`, { + query: req.query, + payload, }) + return res.json(payload) } catch (err) { + logger.error(`Error in bridgeLimitsController`, { + query: req.query, + error: err.message, + stack: err.stack, + }) res.status(500).json({ error: 'An unexpected error occurred in /bridgeLimits. Please try again later.', diff --git a/packages/rest-api/src/controllers/bridgeTxInfoController.ts b/packages/rest-api/src/controllers/bridgeTxInfoController.ts index 01a56f01ca..701c598bce 100644 --- a/packages/rest-api/src/controllers/bridgeTxInfoController.ts +++ b/packages/rest-api/src/controllers/bridgeTxInfoController.ts @@ -3,6 +3,7 @@ import { parseUnits } from '@ethersproject/units' import { Synapse } from '../services/synapseService' import { tokenAddressToToken } from '../utils/tokenAddressToToken' +import { logger } from '../middleware/logger' export const bridgeTxInfoController = async (req, res) => { const errors = validationResult(req) @@ -51,8 +52,18 @@ export const bridgeTxInfoController = async (req, res) => { return txInfo }) ) + + logger.info(`Successful bridgeTxInfoController response`, { + query: req.query, + txInfoArray, + }) res.json(txInfoArray) } catch (err) { + logger.error(`Error in bridgeTxInfoController`, { + query: req.query, + error: err.message, + stack: err.stack, + }) res.status(500).json({ error: 'An unexpected error occurred in /bridgeTxInfo. Please try again later.', diff --git a/packages/rest-api/src/controllers/bridgeTxStatusController.ts b/packages/rest-api/src/controllers/bridgeTxStatusController.ts index 0d4cc34efa..919f6a6c8c 100644 --- a/packages/rest-api/src/controllers/bridgeTxStatusController.ts +++ b/packages/rest-api/src/controllers/bridgeTxStatusController.ts @@ -3,6 +3,7 @@ import { ethers } from 'ethers' import { Synapse } from '../services/synapseService' import { getTokenDecimals } from '../utils/getTokenDecimals' +import { logger } from '../middleware/logger' export const bridgeTxStatusController = async (req, res) => { const errors = validationResult(req) @@ -56,20 +57,46 @@ export const bridgeTxStatusController = async (req, res) => { const tokenDecimals = getTokenDecimals(toInfo.chainID, tokenAddress) const formattedValue = ethers.utils.formatUnits(value, tokenDecimals) - res.json({ + const payload = { status, toInfo: { ...restToInfo, formattedValue: `${formattedValue}`, }, + } + + logger.info(`Successful bridgeTxStatusController response`, { + query: req.query, + payload, }) + res.json(payload) } else { - res.json({ status, toInfo: null }) + const payload = { + status, + toInfo: null, + } + + logger.info(`Successful bridgeTxStatusController response`, { + query: req.query, + payload, + }) + res.json(payload) } } else { - res.json({ status }) + const payload = { status } + + logger.info(`Successful bridgeTxStatusController response`, { + query: req.query, + payload, + }) + res.json(payload) } } catch (err) { + logger.error(`Error in bridgeTxStatusController`, { + query: req.query, + error: err.message, + stack: err.stack, + }) res.status(500).json({ error: 'An unexpected error occurred in /bridgeTxStatus. Please try again later.', diff --git a/packages/rest-api/src/controllers/destinationTokensController.ts b/packages/rest-api/src/controllers/destinationTokensController.ts index e606cd383b..2c93f30ecc 100644 --- a/packages/rest-api/src/controllers/destinationTokensController.ts +++ b/packages/rest-api/src/controllers/destinationTokensController.ts @@ -2,6 +2,7 @@ import { validationResult } from 'express-validator' import { tokenAddressToToken } from '../utils/tokenAddressToToken' import { BRIDGE_ROUTE_MAPPING } from '../utils/bridgeRouteMapping' +import { logger } from '../middleware/logger' export const destinationTokensController = async (req, res) => { const errors = validationResult(req) @@ -16,10 +17,20 @@ export const destinationTokensController = async (req, res) => { const constructedKey = `${fromTokenInfo.symbol}-${fromChain}` - const options = BRIDGE_ROUTE_MAPPING[constructedKey] + const payload = BRIDGE_ROUTE_MAPPING[constructedKey] - res.json(options) + logger.info(`Successful destinationTokensController response`, { + query: req.query, + payload, + }) + + res.json(payload) } catch (err) { + logger.error(`Error in destinationTokensController`, { + query: req.query, + error: err.message, + stack: err.stack, + }) res.status(500).json({ error: 'An unexpected error occurred in /destinationTokens. Please try again later.', diff --git a/packages/rest-api/src/controllers/destinationTxController.ts b/packages/rest-api/src/controllers/destinationTxController.ts index bedc02c7f6..dc951976d8 100644 --- a/packages/rest-api/src/controllers/destinationTxController.ts +++ b/packages/rest-api/src/controllers/destinationTxController.ts @@ -3,6 +3,7 @@ import { ethers } from 'ethers' import { getTokenDecimals } from '../utils/getTokenDecimals' import { tokenAddressToToken } from '../utils/tokenAddressToToken' +import { logger } from '../middleware/logger' export const destinationTxController = async (req, res) => { const errors = validationResult(req) @@ -54,7 +55,7 @@ export const destinationTxController = async (req, res) => { const tokenDecimals = getTokenDecimals(chainID, tokenAddress) const formattedValue = ethers.utils.formatUnits(value, tokenDecimals) - res.json({ + const payload = { status: 'completed', toInfo: { chainID, @@ -62,11 +63,31 @@ export const destinationTxController = async (req, res) => { tokenSymbol: tokenInfo ? tokenInfo?.symbol : null, formattedValue: `${formattedValue}`, }, + } + + logger.info(`Successful destinationTxController response`, { + query: req.query, + payload, }) + res.json(payload) } else { - res.json({ status: 'pending', toInfo: null }) + const payload = { + status: 'pending', + toInfo: null, + } + + logger.info(`Successful destinationTxController response`, { + query: req.query, + payload, + }) + res.json(payload) } } catch (err) { + logger.error(`Error in destinationTxController`, { + query: req.query, + error: err.message, + stack: err.stack, + }) res.status(500).json({ error: 'An unexpected error occurred in /destinationTx. Please try again later.', diff --git a/packages/rest-api/src/controllers/indexController.ts b/packages/rest-api/src/controllers/indexController.ts index f0c8380ddf..4cbb5ec995 100644 --- a/packages/rest-api/src/controllers/indexController.ts +++ b/packages/rest-api/src/controllers/indexController.ts @@ -1,7 +1,8 @@ import * as tokensList from '../constants/bridgeable' import { CHAINS_ARRAY } from '../constants/chains' +import { logger } from '../middleware/logger' -export const indexController = async (_req, res) => { +export const indexController = async (req, res) => { try { const tokensWithChains = Object.values(tokensList).map((token: any) => ({ symbol: token.symbol, @@ -13,15 +14,23 @@ export const indexController = async (_req, res) => { ), })) - res.json({ + const payload = { message: 'Welcome to the Synapse REST API for swap and bridge quotes', availableChains: CHAINS_ARRAY.map((chain) => ({ name: chain.name, id: chain.id, })), availableTokens: tokensWithChains, - }) + } + + logger.info(`Successful indexController response`, { query: req.query }) + res.json(payload) } catch (err) { + logger.error(`Error in indexController`, { + query: req.query, + error: err.message, + stack: err.stack, + }) res.status(500).json({ error: 'An unexpected error occurred in /. Please try again later.', details: err.message, diff --git a/packages/rest-api/src/controllers/swapController.ts b/packages/rest-api/src/controllers/swapController.ts index ac695af971..f6eaa1f882 100644 --- a/packages/rest-api/src/controllers/swapController.ts +++ b/packages/rest-api/src/controllers/swapController.ts @@ -4,6 +4,7 @@ import { BigNumber } from '@ethersproject/bignumber' import { Synapse } from '../services/synapseService' import { tokenAddressToToken } from '../utils/tokenAddressToToken' +import { logger } from '../middleware/logger' export const swapController = async (req, res) => { const errors = validationResult(req) @@ -29,11 +30,22 @@ export const swapController = async (req, res) => { toTokenInfo.decimals ) - res.json({ + const payload = { ...quote, maxAmountOut: formattedMaxAmountOut, + } + + logger.info(`Successful swapController response`, { + query: req.query, + payload, }) + res.json(payload) } catch (err) { + logger.error(`Error in swapController`, { + query: req.query, + error: err.message, + stack: err.stack, + }) res.status(500).json({ error: 'An unexpected error occurred in /swap. Please try again later.', details: err.message, diff --git a/packages/rest-api/src/controllers/swapTxInfoController.ts b/packages/rest-api/src/controllers/swapTxInfoController.ts index 49f63891db..034585e59b 100644 --- a/packages/rest-api/src/controllers/swapTxInfoController.ts +++ b/packages/rest-api/src/controllers/swapTxInfoController.ts @@ -3,6 +3,7 @@ import { parseUnits } from '@ethersproject/units' import { Synapse } from '../services/synapseService' import { tokenAddressToToken } from '../utils/tokenAddressToToken' +import { logger } from '../middleware/logger' export const swapTxInfoController = async (req, res) => { const errors = validationResult(req) @@ -24,7 +25,7 @@ export const swapTxInfoController = async (req, res) => { amountInWei ) - const txInfo = await Synapse.swap( + const payload = await Synapse.swap( Number(chain), address, fromToken, @@ -32,8 +33,17 @@ export const swapTxInfoController = async (req, res) => { quote.query ) - res.json(txInfo) + logger.info(`Successful swapTxInfoController response`, { + query: req.query, + payload, + }) + res.json(payload) } catch (err) { + logger.error(`Error in swapTxInfoController`, { + query: req.query, + error: err.message, + stack: err.stack, + }) res.status(500).json({ error: 'An unexpected error occurred in /swapTxInfo. Please try again later.', diff --git a/packages/rest-api/src/controllers/synapseTxIdController.ts b/packages/rest-api/src/controllers/synapseTxIdController.ts index d8258833a2..41331c2f25 100644 --- a/packages/rest-api/src/controllers/synapseTxIdController.ts +++ b/packages/rest-api/src/controllers/synapseTxIdController.ts @@ -1,6 +1,7 @@ import { validationResult } from 'express-validator' import { Synapse } from '../services/synapseService' +import { logger } from '../middleware/logger' export const synapseTxIdController = async (req, res) => { const errors = validationResult(req) @@ -17,8 +18,21 @@ export const synapseTxIdController = async (req, res) => { txHash ) - res.json({ synapseTxId }) + const payload = { + synapseTxId, + } + + logger.info(`Successful synapseTxIdController response`, { + query: req.query, + payload, + }) + res.json(payload) } catch (err) { + logger.error(`Error in synapseTxIdController`, { + query: req.query, + error: err.message, + stack: err.stack, + }) res.status(500).json({ error: 'An unexpected error occurred in /synapseTxId. Please try again later.', diff --git a/packages/rest-api/src/controllers/tokenListController.ts b/packages/rest-api/src/controllers/tokenListController.ts index b6cc4d8e25..2da060164b 100644 --- a/packages/rest-api/src/controllers/tokenListController.ts +++ b/packages/rest-api/src/controllers/tokenListController.ts @@ -1,5 +1,7 @@ import * as tokenList from '../constants/bridgeable' +import { logger } from '../middleware/logger' -export const tokenListController = async (_req, res) => { +export const tokenListController = async (req, res) => { + logger.info(`Successful tokenListController response`, { query: req.query }) res.json(tokenList) } diff --git a/packages/rest-api/src/middleware/logger.ts b/packages/rest-api/src/middleware/logger.ts new file mode 100644 index 0000000000..1e77f4ef7f --- /dev/null +++ b/packages/rest-api/src/middleware/logger.ts @@ -0,0 +1,26 @@ +import { Writable } from 'stream' + +import winston from 'winston' + +const transports = [] + +if (process.env.NODE_ENV === 'test') { + transports.push( + new winston.transports.Stream({ + stream: new Writable({ + write: () => {}, + }), + }) + ) +} else { + transports.push(new winston.transports.Console()) +} + +export const logger = winston.createLogger({ + level: 'info', + format: winston.format.combine( + winston.format.timestamp(), + winston.format.json() + ), + transports, +}) diff --git a/yarn.lock b/yarn.lock index e8daf537c4..a69c7f75db 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1906,6 +1906,11 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== +"@colors/colors@1.6.0", "@colors/colors@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" + integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== + "@commander-js/extra-typings@^12.0.1": version "12.1.0" resolved "https://registry.yarnpkg.com/@commander-js/extra-typings/-/extra-typings-12.1.0.tgz#5441bae756d326d34f1b9dceb0d78dbf5bc05d81" @@ -1918,6 +1923,15 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@dabh/diagnostics@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" + integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + "@date-io/core@^2.15.0", "@date-io/core@^2.17.0": version "2.17.0" resolved "https://registry.yarnpkg.com/@date-io/core/-/core-2.17.0.tgz#360a4d0641f069776ed22e457876e8a8a58c205e" @@ -9621,6 +9635,11 @@ dependencies: "@types/jest" "*" +"@types/triple-beam@^1.3.2": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" + integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== + "@types/trusted-types@^2.0.2": version "2.0.7" resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" @@ -13705,7 +13724,7 @@ color-support@^1.1.2: resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== -color@^3.1.2: +color@^3.1.2, color@^3.1.3: version "3.2.1" resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== @@ -13736,6 +13755,14 @@ colorette@^2.0.10, colorette@^2.0.16: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== +colorspace@1.1.x: + version "1.1.4" + resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243" + integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== + dependencies: + color "^3.1.3" + text-hex "1.0.x" + columnify@^1.5.4: version "1.6.0" resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.6.0.tgz#6989531713c9008bb29735e61e37acf5bd553cf3" @@ -15985,6 +16012,11 @@ emoticon@^4.0.1: resolved "https://registry.yarnpkg.com/emoticon/-/emoticon-4.1.0.tgz#d5a156868ee173095627a33de3f1e914c3dde79e" integrity sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ== +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + encode-utf8@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda" @@ -18019,6 +18051,11 @@ fdir@^6.1.1: resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.3.0.tgz#fcca5a23ea20e767b15e081ee13b3e6488ee0bb0" integrity sha512-QOnuT+BOtivR77wYvCWHfGt9s4Pz1VIMbD463vegT5MLqNXy8rYFT/lPVEqf/bhYeT6qmqrNHhsX+rWwe3rOCQ== +fecha@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" + integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== + feed@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/feed/-/feed-4.2.2.tgz#865783ef6ed12579e2c44bbef3c9113bc4956a7e" @@ -18283,6 +18320,11 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== + focus-lock@^0.8.0: version "0.8.1" resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.8.1.tgz#bb36968abf77a2063fa173cb6c47b12ac8599d33" @@ -22744,6 +22786,11 @@ klona@^2.0.4: resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA== +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + kysely@^0.26.3: version "0.26.3" resolved "https://registry.yarnpkg.com/kysely/-/kysely-0.26.3.tgz#45fdd0153d8c9418b0ea9a6f05ed46b95ed27678" @@ -23240,6 +23287,18 @@ log-update@^4.0.0: slice-ansi "^4.0.0" wrap-ansi "^6.2.0" +logform@^2.6.0, logform@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.6.1.tgz#71403a7d8cae04b2b734147963236205db9b3df0" + integrity sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA== + dependencies: + "@colors/colors" "1.6.0" + "@types/triple-beam" "^1.3.2" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^2.3.1" + triple-beam "^1.3.0" + logrocket-react@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/logrocket-react/-/logrocket-react-6.0.3.tgz#62c2ce18b9197058f5ba60e54e3f2b084d6588ee" @@ -26386,6 +26445,13 @@ once@~1.3.0: dependencies: wrappy "1" +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" @@ -29371,7 +29437,7 @@ readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stre string_decoder "^1.1.1" util-deprecate "^1.0.1" -"readable-stream@^3.6.2 || ^4.4.2", readable-stream@^4.0.0: +"readable-stream@^3.6.2 || ^4.4.2", readable-stream@^4.0.0, readable-stream@^4.5.2: version "4.5.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.5.2.tgz#9e7fc4c45099baeed934bff6eb97ba6cf2729e09" integrity sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g== @@ -31725,6 +31791,11 @@ stable@^0.1.8: resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== + stack-utils@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.5.tgz#a19b0b01947e0029c8e451d5d61a498f5bb1471b" @@ -32882,6 +32953,11 @@ text-extensions@^1.0.0: resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -33148,6 +33224,11 @@ trim@0.0.1: resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" integrity sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ== +triple-beam@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984" + integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== + trough@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" @@ -36151,6 +36232,32 @@ wildcard@^2.0.0: resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== +winston-transport@^4.7.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.8.0.tgz#a15080deaeb80338455ac52c863418c74fcf38ea" + integrity sha512-qxSTKswC6llEMZKgCQdaWgDuMJQnhuvF5f2Nk3SNXc4byfQ+voo2mX1Px9dkNOuR8p0KAjfPG29PuYUSIb+vSA== + dependencies: + logform "^2.6.1" + readable-stream "^4.5.2" + triple-beam "^1.3.0" + +winston@^3.14.2: + version "3.14.2" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.14.2.tgz#94ce5fd26d374f563c969d12f0cd9c641065adab" + integrity sha512-CO8cdpBB2yqzEf8v895L+GNKYJiEq8eKlHU38af3snQBQ+sdAIUepjMSguOIJC7ICbzm0ZI+Af2If4vIJrtmOg== + dependencies: + "@colors/colors" "^1.6.0" + "@dabh/diagnostics" "^2.0.2" + async "^3.2.3" + is-stream "^2.0.0" + logform "^2.6.0" + one-time "^1.0.0" + readable-stream "^3.4.0" + safe-stable-stringify "^2.3.1" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.7.0" + word-wrap@^1.2.5, word-wrap@~1.2.3: version "1.2.5" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"