diff --git a/apps/cli/package.json b/apps/cli/package.json index ca7404196..3b46584ec 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -23,7 +23,9 @@ "date-prompt": "^1.0.0", "inquirer": "^9.2.12", "inquirer-autocomplete-prompt": "^3.0.1", - "vorpal": "^1.12.0" + "vorpal": "^1.12.0", + "winston": "^3.11.0", + "winston-daily-rotate-file": "^4.7.1" }, "devDependencies": { "@types/inquirer": "9.0.7", diff --git a/apps/cli/src/commands/operator-control/operator-runtime.ts b/apps/cli/src/commands/operator-control/operator-runtime.ts index cd093e1b1..939872b1d 100644 --- a/apps/cli/src/commands/operator-control/operator-runtime.ts +++ b/apps/cli/src/commands/operator-control/operator-runtime.ts @@ -1,4 +1,5 @@ import Vorpal from "vorpal"; +import Logger from "../../utils/Logger.js" import { getSignerFromPrivateKey, operatorRuntime, listOwnersForOperator, Challenge, PublicNodeBucketInformation } from "@sentry/core"; /** @@ -62,7 +63,13 @@ export function bootOperator(cli: Vorpal) { stopFunction = await operatorRuntime( signer, undefined, - (log: string) => this.log(log), + (log: string) => { + if (log.startsWith("Error")) { + Logger.error(log); + return; + } + Logger.log(log) + }, selectedOwners, (publicNodeData: PublicNodeBucketInformation | undefined, challenge: Challenge, message: string) => { const errorMessage = `The comparison between public node and challenge failed:\n` + diff --git a/apps/cli/src/utils/Logger.ts b/apps/cli/src/utils/Logger.ts new file mode 100644 index 000000000..914f97a8d --- /dev/null +++ b/apps/cli/src/utils/Logger.ts @@ -0,0 +1,75 @@ +import path from 'path'; +import fs from 'fs'; +import DailyRotateFile from 'winston-daily-rotate-file'; +import winston from 'winston'; + +let logger: winston.Logger; +const getLogger = () => { + if (!logger) { + const transports = []; + + transports.push( + new winston.transports.Console({ + format: winston.format.printf((log: { message: string }) => log.message), + }) + ) + + const LOG_PATH = getLogPath(); + mkdir(LOG_PATH); + mkdir(path.join(LOG_PATH, 'errors')); + + transports.push( + new DailyRotateFile({ + dirname: LOG_PATH, + filename: 'combined', + datePattern: 'yyyyMMDD', + extension: '.log', + maxFiles: '3d' + }), + ) + + transports.push( + new DailyRotateFile({ + dirname: path.join(LOG_PATH, 'errors'), + filename: 'error', + datePattern: 'yyyyMMDD', + level: 'error', + extension: '.log', + maxFiles: '14d' + }) + ) + + logger = winston.createLogger({ + transports + }); + } + + return logger; +}; + +// Return the os specific app data folder +// OS X - '/Users/user/Library/Preferences/sentry-cli/logs' +// Windows - 'C:\Users\user\AppData\Roaming\sentry-cli\logs' +// Linux - '/home/user/.local/share/sentry-cli/logs' +const getLogPath = (): string => { + const root = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Preferences' : process.env.HOME + "/.local/share"); + return path.join(root, 'sentry-cli', 'logs') +} + +const mkdir = (_path: string): void => { + if (!fs.existsSync(_path)) { + fs.mkdirSync(_path, { recursive: true }); + } +} + +const log = (...args: any): void => { + getLogger().info({ timestamp: new Date().toLocaleString(), level: 'INFO', message: args, PID: process.pid }); +}; + +const error = (...args: any): void => { + getLogger().error({ timestamp: new Date().toLocaleString(), level: 'ERROR', message: args, PID: process.pid }); +}; + +export default { + log, error +} \ No newline at end of file diff --git a/apps/sentry-client-desktop/electron/main.ts b/apps/sentry-client-desktop/electron/main.ts index caba13b08..1cebf8095 100644 --- a/apps/sentry-client-desktop/electron/main.ts +++ b/apps/sentry-client-desktop/electron/main.ts @@ -9,6 +9,8 @@ import {autoUpdater} from 'electron-updater'; const isWindows = os.platform() === "win32"; +log.initialize(); + //------------------------------------------------------------------- // Logging // diff --git a/apps/sentry-client-desktop/src/components/blockpass/Blockpass.tsx b/apps/sentry-client-desktop/src/components/blockpass/Blockpass.tsx index a92654ee0..24454209d 100644 --- a/apps/sentry-client-desktop/src/components/blockpass/Blockpass.tsx +++ b/apps/sentry-client-desktop/src/components/blockpass/Blockpass.tsx @@ -1,5 +1,6 @@ import {PropsWithChildren, useState} from "react"; import {CountryDropdown} from "@/components/blockpass/CountryDropdown"; +import log from "electron-log"; interface BlockpassProps { onClick?: () => void; @@ -24,7 +25,7 @@ export function Blockpass({onClick = () => {}, children = "Begin KYC"}: PropsWit return window.electron.openExternal(`https://verify-with.blockpass.org/?clientId=xai_node_007da`); } } else { - console.log("Please select a country"); + log.info("Please select a country"); } } diff --git a/apps/sentry-client-desktop/src/features/home/SentryWallet.tsx b/apps/sentry-client-desktop/src/features/home/SentryWallet.tsx index b1c260a7d..fe8b793f4 100644 --- a/apps/sentry-client-desktop/src/features/home/SentryWallet.tsx +++ b/apps/sentry-client-desktop/src/features/home/SentryWallet.tsx @@ -26,6 +26,7 @@ import {AssignKeysSentryNotRunning} from "@/components/AssignKeysSentryNotRunnin import {GrRefresh} from "react-icons/gr"; import {LuListChecks} from "react-icons/lu"; import {useStorage} from "@/features/storage"; +import log from "electron-log"; // TODO -> replace with dynamic value later export const recommendedFundingBalance = ethers.parseEther("0.005"); @@ -84,10 +85,10 @@ export function SentryWallet() { }, 2000); }) .catch(err => { - console.error('Unable to copy to clipboard: ', err); + log.error('Unable to copy to clipboard: ', err); }); } else { - console.error('Clipboard API not available, unable to copy to clipboard'); + log.error('Clipboard API not available, unable to copy to clipboard'); } } @@ -101,10 +102,10 @@ export function SentryWallet() { }, 2000); }) .catch(err => { - console.error('Unable to copy to clipboard: ', err); + log.error('Unable to copy to clipboard: ', err); }); } else { - console.error('Clipboard API not available, unable to copy to clipboard'); + log.error('Clipboard API not available, unable to copy to clipboard'); } } diff --git a/apps/sentry-client-desktop/src/features/home/dashboard/SentryNodeStatusCard.tsx b/apps/sentry-client-desktop/src/features/home/dashboard/SentryNodeStatusCard.tsx index 349677e3e..09d2fbfaa 100644 --- a/apps/sentry-client-desktop/src/features/home/dashboard/SentryNodeStatusCard.tsx +++ b/apps/sentry-client-desktop/src/features/home/dashboard/SentryNodeStatusCard.tsx @@ -8,6 +8,7 @@ import {useBalance} from "@/hooks/useBalance"; import {recommendedFundingBalance} from "@/features/home/SentryWallet"; import {getLatestChallenge} from "@sentry/core"; import {ReactNode, useEffect, useState} from "react"; +import log from "electron-log"; export function SentryNodeStatusCard() { const {publicKey} = useOperator(); @@ -26,7 +27,7 @@ export function SentryNodeStatusCard() { :
Error retrieving challenge data
); } catch (error) { - console.error('Error fetching latest challenge:', error); + log.error('Error fetching latest challenge:', error); setTimeAgoString(
Error fetching latest challenge
); } }; diff --git a/apps/sentry-client-desktop/src/features/home/modals/ExportSentryDrawer.tsx b/apps/sentry-client-desktop/src/features/home/modals/ExportSentryDrawer.tsx index 21e9bfa1f..68307e27e 100644 --- a/apps/sentry-client-desktop/src/features/home/modals/ExportSentryDrawer.tsx +++ b/apps/sentry-client-desktop/src/features/home/modals/ExportSentryDrawer.tsx @@ -5,6 +5,7 @@ import {useOperator} from "../../operator"; import {PiCopy} from "react-icons/pi"; import {useState} from "react"; import {BiLoaderAlt} from "react-icons/bi"; +import log from "electron-log"; export function ExportSentryDrawer() { const setDrawerState = useSetAtom(drawerStateAtom); @@ -21,10 +22,10 @@ export function ExportSentryDrawer() { }, 2000); }) .catch(err => { - console.error('Unable to copy to clipboard: ', err); + log.error('Unable to copy to clipboard: ', err); }); } else { - console.error('Clipboard API not available, unable to copy to clipboard'); + log.error('Clipboard API not available, unable to copy to clipboard'); } } diff --git a/apps/sentry-client-desktop/src/features/home/modals/actions-required/FundsInSentryWalletCard.tsx b/apps/sentry-client-desktop/src/features/home/modals/actions-required/FundsInSentryWalletCard.tsx index dd28f9ad9..6e59bff3d 100644 --- a/apps/sentry-client-desktop/src/features/home/modals/actions-required/FundsInSentryWalletCard.tsx +++ b/apps/sentry-client-desktop/src/features/home/modals/actions-required/FundsInSentryWalletCard.tsx @@ -9,6 +9,7 @@ import {useOperator} from "@/features/operator"; import {useState} from "react"; import {accruingStateAtom} from "@/hooks/useAccruingInfo"; import {useAtomValue} from "jotai"; +import log from "electron-log"; export function FundsInSentryWalletCard() { const {isLoading: isOperatorLoading, publicKey: operatorAddress} = useOperator(); @@ -26,10 +27,10 @@ export function FundsInSentryWalletCard() { }, 2000); }) .catch(err => { - console.error('Unable to copy to clipboard: ', err); + log.error('Unable to copy to clipboard: ', err); }); } else { - console.error('Clipboard API not available, unable to copy to clipboard'); + log.error('Clipboard API not available, unable to copy to clipboard'); } } diff --git a/apps/sentry-client-desktop/src/features/keys/HasKeys.tsx b/apps/sentry-client-desktop/src/features/keys/HasKeys.tsx index 886bf89fc..3f4a4f69b 100644 --- a/apps/sentry-client-desktop/src/features/keys/HasKeys.tsx +++ b/apps/sentry-client-desktop/src/features/keys/HasKeys.tsx @@ -23,6 +23,7 @@ import {ethers} from "ethers"; import {BiLoaderAlt} from "react-icons/bi"; import {useGetWalletBalance} from "@/hooks/useGetWalletBalance"; import {useGetSingleWalletBalance} from "@/hooks/useGetSingleWalletBalance"; +import log from "electron-log"; interface HasKeysProps { combinedOwners: string[], @@ -213,10 +214,10 @@ export function HasKeys({combinedOwners, combinedLicensesMap, statusMap, isWalle }, 1500); }) .catch(err => { - console.error('Unable to copy to clipboard: ', err); + log.error('Unable to copy to clipboard: ', err); }); } else { - console.error('Clipboard API not available, unable to copy to clipboard'); + log.error('Clipboard API not available, unable to copy to clipboard'); } } diff --git a/apps/sentry-client-desktop/src/features/keys/StatusPulse.tsx b/apps/sentry-client-desktop/src/features/keys/StatusPulse.tsx index 8fdf39403..74dbf012c 100644 --- a/apps/sentry-client-desktop/src/features/keys/StatusPulse.tsx +++ b/apps/sentry-client-desktop/src/features/keys/StatusPulse.tsx @@ -1,3 +1,5 @@ +import log from "electron-log"; + interface PulseStyle { size?: "sm" | "md" } @@ -16,7 +18,7 @@ export function GreenPulse({size="sm"}: PulseStyle) { pulseH = "1.25rem"; break; default: - console.log("Invalid size"); // Handle the case where size is none of the specified values + log.info("Invalid size"); // Handle the case where size is none of the specified values } const greenPulseStyle = { @@ -48,7 +50,7 @@ export function YellowPulse({size="sm"}: PulseStyle) { pulseH = "1.25rem"; break; default: - console.log("Invalid size"); // Handle the case where size is none of the specified values + log.info("Invalid size"); // Handle the case where size is none of the specified values } const yellowPulseStyle = { diff --git a/apps/sentry-client-desktop/src/features/storage/useStorage.tsx b/apps/sentry-client-desktop/src/features/storage/useStorage.tsx index d075926b5..61388ebe7 100644 --- a/apps/sentry-client-desktop/src/features/storage/useStorage.tsx +++ b/apps/sentry-client-desktop/src/features/storage/useStorage.tsx @@ -1,5 +1,6 @@ import {useEffect, useState} from 'react'; import {atom, useAtom} from 'jotai'; +import log from "electron-log"; const dataAtom = atom(undefined); @@ -57,7 +58,7 @@ export function useStorage(): IUseStorageResponse { await window.ipcRenderer.invoke('fs-writeFileSync', filePath, JSON.stringify(newData)); setData(newData); } catch (error) { - console.error(error); + log.error(error); } finally { setLoading(false); } @@ -70,7 +71,7 @@ export function useStorage(): IUseStorageResponse { await window.ipcRenderer.invoke('fs-unlinkSync', filePath); setData(undefined); } catch (error) { - console.error(error); + log.error(error); } finally { setLoading(false); } diff --git a/apps/sentry-client-desktop/src/hooks/useOperatorRuntime.ts b/apps/sentry-client-desktop/src/hooks/useOperatorRuntime.ts index bf3b8d28d..11a4ae5c5 100644 --- a/apps/sentry-client-desktop/src/hooks/useOperatorRuntime.ts +++ b/apps/sentry-client-desktop/src/hooks/useOperatorRuntime.ts @@ -3,6 +3,7 @@ import {useOperator} from "@/features/operator"; import {atom, useAtom} from "jotai"; import {useEffect, useState} from "react"; import {useStorage} from "@/features/storage"; +import log from "electron-log"; function onAssertionMissMatch(publicNodeData: PublicNodeBucketInformation, challenge: Challenge, message: string) { const errorMessage = `The comparison between public node and challenge failed:\n` + @@ -36,16 +37,20 @@ export function useOperatorRuntime() { } }, [signer]); - function writeLog(log: string) { - console.info(log); // for debugging purposes - const _logs = runtimeLogs.concat([]); - if (_logs.length === 1000) { - _logs.shift(); - } + function writeLog(message: string) { + if (message.startsWith("Error")) { + log.error(message); + } else { + log.info(message); + } + const _logs = runtimeLogs.concat([]); + if (_logs.length === 1000) { + _logs.shift(); + } - _logs.push(log); - setRuntimeLogs(_logs); - } + _logs.push(message); + setRuntimeLogs(_logs); + } async function startRuntime() { if (!sentryRunning && stop === undefined) { diff --git a/apps/sentry-client-desktop/src/main.tsx b/apps/sentry-client-desktop/src/main.tsx index ebfc659a0..caaefa512 100644 --- a/apps/sentry-client-desktop/src/main.tsx +++ b/apps/sentry-client-desktop/src/main.tsx @@ -6,6 +6,7 @@ import * as Sentry from "@sentry/react"; import {HttpClient} from "@sentry/integrations"; import "./index.css"; import {createRoutesFromChildren, matchRoutes, useLocation, useNavigationType} from "react-router-dom"; +import log from "electron-log"; const rootElement = document.getElementById('root')! @@ -55,5 +56,5 @@ postMessage({payload: 'removeLoading'}, '*') // Use contextBridge window.ipcRenderer.on('main-process-message', (_event, message) => { - console.log(message) + log.info(message) }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d870fa961..1bf25b1e0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -63,6 +63,12 @@ importers: vorpal: specifier: ^1.12.0 version: 1.12.0 + winston: + specifier: ^3.11.0 + version: 3.11.0 + winston-daily-rotate-file: + specifier: ^4.7.1 + version: 4.7.1(winston@3.11.0) devDependencies: '@types/inquirer': specifier: 9.0.7 @@ -2038,12 +2044,25 @@ packages: dev: false optional: true + /@colors/colors@1.6.0: + resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} + engines: {node: '>=0.1.90'} + dev: false + /@cspotcode/source-map-support@0.8.1: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} dependencies: '@jridgewell/trace-mapping': 0.3.9 + /@dabh/diagnostics@2.0.3: + resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==} + dependencies: + colorspace: 1.1.4 + enabled: 2.0.0 + kuler: 2.0.0 + dev: false + /@derhuerst/cli-on-key@0.1.0: resolution: {integrity: sha512-+Q3J+a/4fSyR9SIsV9PEW24AuIHyMwsZ3yNd1nGGOXKIz0aoqovBHE+LQSd7FkfV6ZJi0N1Mw2RwaZq2xMa3BA==} engines: {node: '>=6'} @@ -6444,6 +6463,10 @@ packages: resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} dev: false + /@types/triple-beam@1.3.5: + resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} + dev: false + /@types/trusted-types@2.0.5: resolution: {integrity: sha512-I3pkr8j/6tmQtKV/ZzHtuaqYSQvyjGRKH4go60Rr0IDLlFxuRT5V32uvB1mecM5G1EVAUyF/4r4QZ1GHgz+mxA==} dev: false @@ -7973,7 +7996,6 @@ packages: /async@3.2.4: resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} - dev: true /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -9005,6 +9027,20 @@ packages: /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + /color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + dev: false + + /color@3.2.1: + resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==} + dependencies: + color-convert: 1.9.3 + color-string: 1.9.1 + dev: false + /colord@2.9.3: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} dev: false @@ -9018,6 +9054,13 @@ packages: engines: {node: '>=0.1.90'} dev: true + /colorspace@1.1.4: + resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==} + dependencies: + color: 3.2.1 + text-hex: 1.0.0 + dev: false + /combine-promises@1.2.0: resolution: {integrity: sha512-VcQB1ziGD0NXrhKxiwyNbCDmRzs/OShMs2GqW2DlU2A/Sd0nQxE1oWDAE5O0ygSx5mgQOn9eIFh7yKPgFRVkPQ==} engines: {node: '>=10'} @@ -10276,6 +10319,10 @@ packages: resolution: {integrity: sha512-dqx7eA9YaqyvYtUhJwT4rC1HIp82j5ybS1/vQ42ur+jBe17dJMwZE4+gvL1XadSFfxaPFFGt3Xsw+Y8akThDlw==} dev: false + /enabled@2.0.0: + resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} + dev: false + /encode-utf8@1.0.3: resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} dev: false @@ -11157,6 +11204,7 @@ packages: dependencies: is-hex-prefixed: 1.0.0 strip-hex-prefix: 1.0.0 + bundledDependencies: false /eval@0.1.8: resolution: {integrity: sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==} @@ -11421,6 +11469,10 @@ packages: pend: 1.2.0 dev: true + /fecha@4.2.3: + resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} + dev: false + /feed@4.2.2: resolution: {integrity: sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==} engines: {node: '>=0.4.0'} @@ -11476,6 +11528,12 @@ packages: webpack: 5.89.0 dev: false + /file-stream-rotator@0.6.1: + resolution: {integrity: sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==} + dependencies: + moment: 2.29.4 + dev: false + /file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} dev: false @@ -11601,6 +11659,10 @@ packages: - encoding dev: false + /fn.name@1.1.0: + resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} + dev: false + /follow-redirects@1.15.2(debug@4.3.4): resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} engines: {node: '>=4.0'} @@ -13125,6 +13187,10 @@ packages: /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + /is-arrayish@0.3.2: + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + dev: false + /is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} dependencies: @@ -13819,6 +13885,10 @@ packages: engines: {node: '>=6'} dev: false + /kuler@2.0.0: + resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} + dev: false + /latest-version@7.0.0: resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==} engines: {node: '>=14.16'} @@ -14128,6 +14198,18 @@ packages: cli-cursor: 1.0.2 dev: false + /logform@2.6.0: + resolution: {integrity: sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==} + engines: {node: '>= 12.0.0'} + dependencies: + '@colors/colors': 1.6.0 + '@types/triple-beam': 1.3.5 + fecha: 4.2.3 + ms: 2.1.3 + safe-stable-stringify: 2.4.3 + triple-beam: 1.4.1 + dev: false + /longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} dev: false @@ -15541,6 +15623,11 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + /object-hash@2.2.0: + resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==} + engines: {node: '>= 6'} + dev: false + /object-hash@3.0.0: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} @@ -15626,6 +15713,12 @@ packages: dependencies: wrappy: 1.0.2 + /one-time@1.0.0: + resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} + dependencies: + fn.name: 1.1.0 + dev: false + /onetime@1.1.0: resolution: {integrity: sha512-GZ+g4jayMqzCRMgB2sol7GiCLjKfS1PINkjmx8spcKce1LiVqcbQreXwqs2YAFXC6R03VIG28ZS31t8M866v6A==} engines: {node: '>=0.10.0'} @@ -18088,6 +18181,12 @@ packages: simple-concat: 1.0.1 dev: true + /simple-swizzle@0.2.2: + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + dependencies: + is-arrayish: 0.3.2 + dev: false + /simple-update-notifier@2.0.0: resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} engines: {node: '>=10'} @@ -18370,6 +18469,10 @@ packages: deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility' dev: false + /stack-trace@0.0.10: + resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} + dev: false + /stacktrace-parser@0.1.10: resolution: {integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==} engines: {node: '>=6'} @@ -18936,6 +19039,10 @@ packages: resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} dev: false + /text-hex@1.0.0: + resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} + dev: false + /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -19072,6 +19179,11 @@ packages: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} dev: false + /triple-beam@1.4.1: + resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==} + engines: {node: '>= 14.0.0'} + dev: false + /trough@2.1.0: resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==} dev: false @@ -20824,6 +20936,45 @@ packages: is-number: 3.0.0 dev: false + /winston-daily-rotate-file@4.7.1(winston@3.11.0): + resolution: {integrity: sha512-7LGPiYGBPNyGHLn9z33i96zx/bd71pjBn9tqQzO3I4Tayv94WPmBNwKC7CO1wPHdP9uvu+Md/1nr6VSH9h0iaA==} + engines: {node: '>=8'} + peerDependencies: + winston: ^3 + dependencies: + file-stream-rotator: 0.6.1 + object-hash: 2.2.0 + triple-beam: 1.4.1 + winston: 3.11.0 + winston-transport: 4.7.0 + dev: false + + /winston-transport@4.7.0: + resolution: {integrity: sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==} + engines: {node: '>= 12.0.0'} + dependencies: + logform: 2.6.0 + readable-stream: 3.6.2 + triple-beam: 1.4.1 + dev: false + + /winston@3.11.0: + resolution: {integrity: sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==} + engines: {node: '>= 12.0.0'} + dependencies: + '@colors/colors': 1.6.0 + '@dabh/diagnostics': 2.0.3 + async: 3.2.4 + is-stream: 2.0.1 + logform: 2.6.0 + one-time: 1.0.0 + readable-stream: 3.6.2 + safe-stable-stringify: 2.4.3 + stack-trace: 0.0.10 + triple-beam: 1.4.1 + winston-transport: 4.7.0 + dev: false + /word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'}