diff --git a/.husky/pre-commit b/.husky/pre-commit index 999ab82..c9bf225 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,5 +1,4 @@ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" -pnpm biome -pnpm test +npx lint-staged && pnpm test diff --git a/lint-staged.config.cjs b/lint-staged.config.cjs new file mode 100644 index 0000000..e498f0b --- /dev/null +++ b/lint-staged.config.cjs @@ -0,0 +1,3 @@ +module.exports = { + "*": ["pnpm biome", "pnpm test"] +} diff --git a/package.json b/package.json index 92ba760..6a26b01 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "clean": "turbo clean && rimraf node_modules .turbo", "build": "turbo build", "dev": "turbo dev", - "biome": "biome check --write --no-errors-on-unmatched", + "biome": "biome check --no-errors-on-unmatched", "changeset": "changeset", "changeset:version": "changeset version", "changeset:release": "changeset publish", @@ -26,6 +26,7 @@ "@commitlint/cli": "^19.3.0", "@commitlint/config-conventional": "^19.2.2", "husky": "^9.0.11", + "lint-staged": "^15.2.7", "rimraf": "^5.0.7", "turbo": "^2.0.3" }, diff --git a/packages/pinorama-client/package.json b/packages/pinorama-client/package.json index 707178d..62a422c 100644 --- a/packages/pinorama-client/package.json +++ b/packages/pinorama-client/package.json @@ -21,9 +21,7 @@ } }, "types": "./dist/types/pinorama-client.d.ts", - "files": [ - "dist" - ], + "files": ["dist"], "scripts": { "clean": "rimraf dist node_modules", "build": "rollup --config" diff --git a/packages/pinorama-client/rollup.config.mjs b/packages/pinorama-client/rollup.config.mjs index 42434d0..d0d3b9a 100644 --- a/packages/pinorama-client/rollup.config.mjs +++ b/packages/pinorama-client/rollup.config.mjs @@ -1,19 +1,19 @@ -import alias from "@rollup/plugin-alias"; -import commonjs from "@rollup/plugin-commonjs"; -import resolve from "@rollup/plugin-node-resolve"; -import terser from "@rollup/plugin-terser"; -import typescript from "@rollup/plugin-typescript"; -import { dts } from "rollup-plugin-dts"; +import alias from "@rollup/plugin-alias" +import commonjs from "@rollup/plugin-commonjs" +import resolve from "@rollup/plugin-node-resolve" +import terser from "@rollup/plugin-terser" +import typescript from "@rollup/plugin-typescript" +import { dts } from "rollup-plugin-dts" -const inputFile = "src/index.ts"; -const outputFileName = "pinorama-client"; +const inputFile = "src/index.ts" +const outputFileName = "pinorama-client" export default [ // Declaration file { input: inputFile, output: [{ file: "dist/types/pinorama-client.d.ts", format: "es" }], - plugins: [dts()], + plugins: [dts()] }, // Browser ESM build @@ -23,21 +23,21 @@ export default [ { file: `dist/browser/${outputFileName}.esm.js`, format: "es", - sourcemap: true, - }, + sourcemap: true + } ], plugins: [ alias({ entries: [ - { find: "./platform/node.js", replacement: "./platform/browser.js" }, - ], + { find: "./platform/node.js", replacement: "./platform/browser.js" } + ] }), resolve({ browser: true }), commonjs(), typescript(), - terser(), + terser() ], - external: ["zod"], + external: ["zod"] }, // // Browser UMD build @@ -92,11 +92,11 @@ export default [ { file: `dist/node/${outputFileName}.mjs`, format: "es", - sourcemap: true, - }, + sourcemap: true + } ], plugins: [resolve(), commonjs(), typescript()], - external: ["zod"], + external: ["zod"] }, // Node.js CJS build @@ -106,10 +106,10 @@ export default [ { file: `dist/node/${outputFileName}.cjs`, format: "cjs", - sourcemap: true, - }, + sourcemap: true + } ], plugins: [resolve(), commonjs(), typescript()], - external: ["zod"], - }, -]; + external: ["zod"] + } +] diff --git a/packages/pinorama-client/src/index.ts b/packages/pinorama-client/src/index.ts index 456c01b..75663b8 100644 --- a/packages/pinorama-client/src/index.ts +++ b/packages/pinorama-client/src/index.ts @@ -1,5 +1,5 @@ -import { z } from "zod"; -import { setTimeout } from "./platform/node.js"; +import { z } from "zod" +import { setTimeout } from "./platform/node.js" const clientOptionsSchema = z.object({ url: z.string(), @@ -7,77 +7,77 @@ const clientOptionsSchema = z.object({ backoff: z.number().min(0), backoffFactor: z.number().min(2), backoffMax: z.number().min(1000), - adminSecret: z.string().optional(), -}); + adminSecret: z.string().optional() +}) -export type PinoramaClientOptions = z.infer; +export type PinoramaClientOptions = z.infer export const defaultClientOptions: Partial = { maxRetries: 5, backoff: 1000, backoffFactor: 2, - backoffMax: 30000, -}; + backoffMax: 30000 +} export class PinoramaClient { /** Pinorama Server URL */ - private url: string; + private url: string /** Maximum number of retry attempts */ - private maxRetries: number; + private maxRetries: number /** Initial backoff delay in milliseconds */ - private backoff: number; + private backoff: number /** Factor by which the backoff delay increases */ - private backoffFactor: number; + private backoffFactor: number /** Maximum backoff delay in milliseconds */ - private backoffMax: number; + private backoffMax: number /** Default headers for HTTP requests */ - private defaultHeaders: Record; + private defaultHeaders: Record constructor(options?: Partial) { const opts = clientOptionsSchema.parse({ ...defaultClientOptions, - ...options, - }); + ...options + }) - this.url = opts.url; - this.maxRetries = opts.maxRetries; - this.backoff = opts.backoff; - this.backoffFactor = opts.backoffFactor; - this.backoffMax = opts.backoffMax; + this.url = opts.url + this.maxRetries = opts.maxRetries + this.backoff = opts.backoff + this.backoffFactor = opts.backoffFactor + this.backoffMax = opts.backoffMax - this.defaultHeaders = this.getDefaultHeaders(opts); + this.defaultHeaders = this.getDefaultHeaders(opts) } private getDefaultHeaders(options: Partial) { const headers: Record = { - "content-type": "application/json", - }; + "content-type": "application/json" + } if (options.adminSecret) { - headers["x-pinorama-admin-secret"] = options.adminSecret; + headers["x-pinorama-admin-secret"] = options.adminSecret } - return headers; + return headers } private async retryOperation(operation: () => Promise): Promise { - let retries = 0; - let currentBackoff = this.backoff; + let retries = 0 + let currentBackoff = this.backoff while (retries < this.maxRetries) { try { - await operation(); - return; + await operation() + return } catch (error) { - console.error("error during operation:", error); - retries++; - if (retries >= this.maxRetries) throw new Error("max retries reached"); - await setTimeout(Math.min(currentBackoff, this.backoffMax)); - currentBackoff *= this.backoffFactor; + console.error("error during operation:", error) + retries++ + if (retries >= this.maxRetries) throw new Error("max retries reached") + await setTimeout(Math.min(currentBackoff, this.backoffMax)) + currentBackoff *= this.backoffFactor } } } @@ -87,13 +87,13 @@ export class PinoramaClient { const response = await fetch(`${this.url}/bulk`, { method: "POST", headers: this.defaultHeaders, - body: JSON.stringify(docs), - }); + body: JSON.stringify(docs) + }) if (response.status !== 201) { - throw new Error("[TODO ERROR]: PinoramaClient.insert failed"); + throw new Error("[TODO ERROR]: PinoramaClient.insert failed") } - }); + }) } public async search(payload: unknown): Promise { @@ -101,18 +101,18 @@ export class PinoramaClient { const response = await fetch(`${this.url}/search`, { method: "POST", headers: this.defaultHeaders, - body: JSON.stringify(payload), - }); + body: JSON.stringify(payload) + }) - const json = await response.json(); + const json = await response.json() if (response.status !== 200) { - throw new Error(json.error); + throw new Error(json.error) } - return json; + return json } catch (error) { - console.error("error searching logs:", error); - throw error; + console.error("error searching logs:", error) + throw error } } } diff --git a/packages/pinorama-client/src/platform/browser.ts b/packages/pinorama-client/src/platform/browser.ts index 7401e23..f196926 100644 --- a/packages/pinorama-client/src/platform/browser.ts +++ b/packages/pinorama-client/src/platform/browser.ts @@ -1,4 +1,4 @@ const setTimeout = (ms: number) => - new Promise((resolve) => window.setTimeout(resolve, ms)); + new Promise((resolve) => window.setTimeout(resolve, ms)) -export { setTimeout }; +export { setTimeout } diff --git a/packages/pinorama-client/src/platform/node.ts b/packages/pinorama-client/src/platform/node.ts index 8ddcf97..a75e025 100644 --- a/packages/pinorama-client/src/platform/node.ts +++ b/packages/pinorama-client/src/platform/node.ts @@ -1,3 +1,3 @@ -import { setTimeout } from "node:timers/promises"; +import { setTimeout } from "node:timers/promises" -export { setTimeout }; +export { setTimeout } diff --git a/packages/pinorama-client/tsconfig.json b/packages/pinorama-client/tsconfig.json index de99eea..baa7821 100644 --- a/packages/pinorama-client/tsconfig.json +++ b/packages/pinorama-client/tsconfig.json @@ -13,17 +13,8 @@ "moduleResolution": "Node", "module": "ESNext", "sourceMap": true, - "lib": [ - "ESNext", - "DOM" - ], + "lib": ["ESNext", "DOM"] }, - "include": [ - "src" - ], - "exclude": [ - "node_modules", - "dist", - "tests" - ] + "include": ["src"], + "exclude": ["node_modules", "dist", "tests"] } diff --git a/packages/pinorama-server/package.json b/packages/pinorama-server/package.json index 1234ce5..6eec584 100644 --- a/packages/pinorama-server/package.json +++ b/packages/pinorama-server/package.json @@ -5,9 +5,7 @@ "type": "module", "types": "./dist/index.d.mts", "exports": "./dist/index.mjs", - "files": [ - "dist" - ], + "files": ["dist"], "scripts": { "clean": "rimraf dist node_modules", "build": "tsc" diff --git a/packages/pinorama-studio/cli.mjs b/packages/pinorama-studio/cli.mjs index 5d9bf1f..92b40e8 100755 --- a/packages/pinorama-studio/cli.mjs +++ b/packages/pinorama-studio/cli.mjs @@ -1,18 +1,18 @@ #! /usr/bin/env node -import { readFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { pipeline } from "node:stream/promises"; -import { fileURLToPath } from "node:url"; -import fastifyCors from "@fastify/cors"; -import fastifyStatic from "@fastify/static"; -import c from "chalk"; -import fastify from "fastify"; -import minimist from "minimist"; -import open from "open"; -import { fastifyPinoramaServer } from "pinorama-server"; -import pinoramaTransport from "pinorama-transport"; +import { readFileSync } from "node:fs" +import os from "node:os" +import path from "node:path" +import { pipeline } from "node:stream/promises" +import { fileURLToPath } from "node:url" +import fastifyCors from "@fastify/cors" +import fastifyStatic from "@fastify/static" +import c from "chalk" +import fastify from "fastify" +import minimist from "minimist" +import open from "open" +import { fastifyPinoramaServer } from "pinorama-server" +import pinoramaTransport from "pinorama-transport" const defaultOptions = { host: "localhost", @@ -22,14 +22,14 @@ const defaultOptions = { server: false, "server-prefix": "/pinorama", "server-db-path": path.resolve(os.tmpdir(), "pinorama.msp"), - "admin-secret": "your-secret", -}; + "admin-secret": "your-secret" +} async function start(options) { - const opts = { ...defaultOptions, ...options }; + const opts = { ...defaultOptions, ...options } - const pj = fileURLToPath(new URL("./package.json", import.meta.url)); - const { version } = JSON.parse(readFileSync(pj, "utf8")); + const pj = fileURLToPath(new URL("./package.json", import.meta.url)) + const { version } = JSON.parse(readFileSync(pj, "utf8")) if (opts.help) { console.log(` @@ -59,63 +59,63 @@ async function start(options) { cat logs | pinorama -l -o pinorama --host 192.168.1.1 --port 8080 pinorama --server --logger -`); - return; +`) + return } if (opts.version) { - console.log(version); - return; + console.log(version) + return } - const isPiped = !process.stdin.isTTY; - opts.server = isPiped || opts.server; + const isPiped = !process.stdin.isTTY + opts.server = isPiped || opts.server - const app = createServer(opts); + const app = createServer(opts) if (opts.server) { app.register(fastifyPinoramaServer, { adminSecret: opts["admin-secret"], dbPath: opts["server-db-path"], - prefix: opts["server-prefix"], - }); + prefix: opts["server-prefix"] + }) } - const studioUrl = `http://${opts.host}:${opts.port}`; - const serverUrl = `${studioUrl}${opts["server-prefix"]}`; + const studioUrl = `http://${opts.host}:${opts.port}` + const serverUrl = `${studioUrl}${opts["server-prefix"]}` app.listen({ host: opts.host, port: opts.port }, async (err) => { - if (err) throw err; + if (err) throw err - const msg = [`${"Pinorama Studio Web:"} ${c.dim(studioUrl)}`]; + const msg = [`${"Pinorama Studio Web:"} ${c.dim(studioUrl)}`] if (opts.server) { - msg.push(`${"Pinorama Server API:"} ${c.dim(serverUrl)}`); - msg.push(`${"Server DB File Path:"} ${c.dim(opts["server-db-path"])}`); + msg.push(`${"Pinorama Server API:"} ${c.dim(serverUrl)}`) + msg.push(`${"Server DB File Path:"} ${c.dim(opts["server-db-path"])}`) } - console.log(msg.join("\n")); + console.log(msg.join("\n")) - opts.open && (await open(studioUrl)); - }); + opts.open && (await open(studioUrl)) + }) if (isPiped) { console.log( c.yellow("Detected piped output. Server mode activated by default.") - ); + ) const stream = pinoramaTransport({ url: serverUrl, batchSize: 1000, - adminSecret: opts["admin-secret"], - }); + adminSecret: opts["admin-secret"] + }) stream.on("error", (error) => { - console.error(error); - }); + console.error(error) + }) - await app.ready(); - pipeline(process.stdin, stream); + await app.ready() + pipeline(process.stdin, stream) } } @@ -126,20 +126,20 @@ function createServer(opts) { transport: { target: "@fastify/one-line-logger", options: { - colorize: true, - }, - }, + colorize: true + } + } } - : false, - }); + : false + }) - app.register(fastifyCors); + app.register(fastifyCors) app.register(fastifyStatic, { - root: fileURLToPath(new URL("dist", import.meta.url)), - }); + root: fileURLToPath(new URL("dist", import.meta.url)) + }) - return app; + return app } start( @@ -154,9 +154,9 @@ start( server: "s", "server-prefix": "e", "server-db-path": "f", - "admin-secret": "k", + "admin-secret": "k" }, boolean: ["server", "open"], - default: defaultOptions, + default: defaultOptions }) -); +) diff --git a/packages/pinorama-studio/package.json b/packages/pinorama-studio/package.json index 945412f..ba04ba0 100644 --- a/packages/pinorama-studio/package.json +++ b/packages/pinorama-studio/package.json @@ -6,10 +6,7 @@ "bin": { "pinorama": "./cli.mjs" }, - "files": [ - "dist", - "cli.mjs" - ], + "files": ["dist", "cli.mjs"], "scripts": { "dev": "vite", "build": "tsc && vite build", @@ -24,9 +21,11 @@ "@radix-ui/react-menubar": "^1.0.4", "@radix-ui/react-slot": "^1.0.2", "@tanstack/react-query": "^5.40.1", + "@tanstack/react-virtual": "^3.5.1", "chalk": "^5.3.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", + "date-fns": "^3.6.0", "fastify": "^4.27.0", "lucide-react": "^0.390.0", "minimist": "^1.2.8", diff --git a/packages/pinorama-studio/src/app.tsx b/packages/pinorama-studio/src/app.tsx index 33f1e63..9627697 100644 --- a/packages/pinorama-studio/src/app.tsx +++ b/packages/pinorama-studio/src/app.tsx @@ -1,8 +1,74 @@ import { useLogs } from "@/hooks" +import { useVirtualizer } from "@tanstack/react-virtual" +import { format } from "date-fns" +import { useRef } from "react" + +function LogLine({ log }: { log: any }) { + const levels = { + 60: { label: "fatal", className: "text-red-900" }, + 50: { label: "error", className: "text-red-600" }, + 40: { label: "warn", className: "text-yellow-500" }, + 30: { label: "info", className: "text-blue-500" }, + 20: { label: "debug", className: "text-green-500" }, + 10: { label: "trace", className: "text-gray-500" } + } + + const { label, className } = levels[log.level] + + return ( + <> + {format(log.time, "Pp")} + {log.req ? ( + <> + + {log.req.method} {log.req.url} + + + ) : null} + {label} + {log.msg} + + ) +} function App() { + const parentRef = useRef(null) + + const rowVirtualizer = useVirtualizer({ + count: 200000, + getScrollElement: () => parentRef.current, + estimateSize: () => 20 + }) + const { data } = useLogs() - return
{JSON.stringify(data)}
+ + if (!data) return null + + return ( + <> +
+
+ {rowVirtualizer.getVirtualItems().map((virtualItem) => { + return ( +
+ +
+ ) + })} +
+
+ + ) } export default App diff --git a/packages/pinorama-studio/src/components/log-line.tsx b/packages/pinorama-studio/src/components/log-line.tsx new file mode 100644 index 0000000..7007d0c --- /dev/null +++ b/packages/pinorama-studio/src/components/log-line.tsx @@ -0,0 +1,41 @@ +import { format } from "date-fns" + +type LogLineProps = { + log: { + req?: { + method: string + url: string + } + time: string + level: number + msg: string + } +} + +export function LogLine({ log }: LogLineProps) { + const levels: Record = { + 60: { label: "fatal", className: "text-red-900" }, + 50: { label: "error", className: "text-red-600" }, + 40: { label: "warn", className: "text-yellow-500" }, + 30: { label: "info", className: "text-blue-500" }, + 20: { label: "debug", className: "text-green-500" }, + 10: { label: "trace", className: "text-gray-500" } + } + + const { label, className } = levels[log.level] + + return ( + <> + {format(log.time, "Pp")} + {log.req ? ( + <> + + {log.req.method} {log.req.url} + + + ) : null} + {label} + {log.msg} + + ) +} diff --git a/packages/pinorama-studio/src/components/pinorama-client-provider.tsx b/packages/pinorama-studio/src/components/pinorama-client-provider.tsx index a97655c..6d6570f 100644 --- a/packages/pinorama-studio/src/components/pinorama-client-provider.tsx +++ b/packages/pinorama-studio/src/components/pinorama-client-provider.tsx @@ -1,23 +1,23 @@ -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query" import { PinoramaClient, - type PinoramaClientOptions, -} from "pinorama-client/browser"; -import { createContext, useContext } from "react"; + type PinoramaClientOptions +} from "pinorama-client/browser" +import { createContext, useContext } from "react" type PinoramaClientProviderProps = { - options: Partial; - children: React.ReactNode; -}; + options: Partial + children: React.ReactNode +} -const PinoramaClientContext = createContext(null); +const PinoramaClientContext = createContext(null) export function PinoramaClientProvider({ options, - children, + children }: PinoramaClientProviderProps) { - const queryClient = new QueryClient(); - const pinoramaClient = new PinoramaClient(options); + const queryClient = new QueryClient() + const pinoramaClient = new PinoramaClient(options) return ( @@ -25,17 +25,17 @@ export function PinoramaClientProvider({ {children} - ); + ) } export const usePinoramaClient = () => { - const context = useContext(PinoramaClientContext); + const context = useContext(PinoramaClientContext) if (context === undefined) { throw new Error( "usePinoramaClient must be used within a PinoramaClientProvider" - ); + ) } - return context; -}; + return context +} diff --git a/packages/pinorama-studio/src/hooks/index.ts b/packages/pinorama-studio/src/hooks/index.ts index 3d32e49..a81faa6 100644 --- a/packages/pinorama-studio/src/hooks/index.ts +++ b/packages/pinorama-studio/src/hooks/index.ts @@ -7,8 +7,10 @@ export const useLogs = () => { const query = useQuery({ queryKey: ["logs"], queryFn: async () => { - const response: any = await client?.search({}) - response.json() + const response: any = await client?.search({ + limit: 200000 + }) + return response.hits.map((hit) => hit.document) } }) diff --git a/packages/pinorama-studio/src/main.tsx b/packages/pinorama-studio/src/main.tsx index 51b40f4..dd5d7ad 100644 --- a/packages/pinorama-studio/src/main.tsx +++ b/packages/pinorama-studio/src/main.tsx @@ -1,17 +1,19 @@ -import React from "react"; -import ReactDOM from "react-dom/client"; +import React from "react" +import ReactDOM from "react-dom/client" -import { PinoramaClientProvider } from "@/components/pinorama-client-provider"; -import { ThemeProvider } from "@/components/theme-provider"; -import App from "./app.tsx"; -import "./globals.css"; +import { PinoramaClientProvider } from "@/components/pinorama-client-provider" +import { ThemeProvider } from "@/components/theme-provider" +import App from "./app.tsx" +import "./globals.css" ReactDOM.createRoot(document.getElementById("app") as HTMLElement).render( - + -); +) diff --git a/packages/pinorama-transport/package.json b/packages/pinorama-transport/package.json index e600d86..4229715 100644 --- a/packages/pinorama-transport/package.json +++ b/packages/pinorama-transport/package.json @@ -8,9 +8,7 @@ "bin": { "pino-pinorama": "./dist/cli.mjs" }, - "files": [ - "dist" - ], + "files": ["dist"], "scripts": { "test": "vitest run", "test:watch": "vitest", diff --git a/packages/pinorama-transport/src/lib.mts b/packages/pinorama-transport/src/lib.mts index 45c5a3e..6f1c002 100644 --- a/packages/pinorama-transport/src/lib.mts +++ b/packages/pinorama-transport/src/lib.mts @@ -1,21 +1,21 @@ -import { setInterval } from "node:timers"; -import abstractTransport from "pino-abstract-transport"; -import { PinoramaClient } from "pinorama-client/node"; +import { setInterval } from "node:timers" +import abstractTransport from "pino-abstract-transport" +import { PinoramaClient } from "pinorama-client/node" -import type { Transform } from "node:stream"; -import type { PinoramaClientOptions } from "pinorama-client/node"; +import type { Transform } from "node:stream" +import type { PinoramaClientOptions } from "pinorama-client/node" type BulkOptions = { - batchSize: number; - flushInterval: number; -}; + batchSize: number + flushInterval: number +} export const defaultBulkOptions: BulkOptions = { batchSize: 100, - flushInterval: 5000, -}; + flushInterval: 5000 +} -export type PinoramaTransportOptions = PinoramaClientOptions & BulkOptions; +export type PinoramaTransportOptions = PinoramaClientOptions & BulkOptions /** * Creates a pino transport that sends logs to a Pinorama server. @@ -32,73 +32,72 @@ export default function pinoramaTransport( "backoff", "backoffFactor", "backoffMax", - "adminSecret", - ]); + "adminSecret" + ]) - const bulkOpts = filterOptions(options, ["batchSize", "flushInterval"]); + const bulkOpts = filterOptions(options, ["batchSize", "flushInterval"]) - const client = new PinoramaClient(clientOpts); + const client = new PinoramaClient(clientOpts) /* build */ const buildFn = async (stream: Transform) => { - const buffer: unknown[] = []; - let flushing = false; + const buffer: unknown[] = [] + let flushing = false const opts: BulkOptions = { batchSize: bulkOpts?.batchSize ?? defaultBulkOptions.batchSize, - flushInterval: - bulkOpts?.flushInterval ?? defaultBulkOptions.flushInterval, - }; + flushInterval: bulkOpts?.flushInterval ?? defaultBulkOptions.flushInterval + } const flush = async () => { - if (buffer.length === 0 || flushing) return; - flushing = true; + if (buffer.length === 0 || flushing) return + flushing = true try { - stream.pause(); - await client.insert(buffer); - buffer.length = 0; + stream.pause() + await client.insert(buffer) + buffer.length = 0 } catch (error) { - console.error("Failed to flush logs:", error); + console.error("Failed to flush logs:", error) } finally { - stream.resume(); - flushing = false; + stream.resume() + flushing = false } - }; + } const intervalId = setInterval(() => { - flush(); - }, opts.flushInterval); + flush() + }, opts.flushInterval) stream.on("data", async (data) => { - buffer.push(data); + buffer.push(data) if (buffer.length >= opts.batchSize) { - await flush(); + await flush() } - }); + }) stream.on("end", async () => { - clearInterval(intervalId); - await flush(); - }); - }; + clearInterval(intervalId) + await flush() + }) + } /* parseLine */ const parseLineFn = (line: string) => { - const obj = JSON.parse(line); + const obj = JSON.parse(line) if (Object.prototype.toString.call(obj) !== "[object Object]") { - throw new Error("not a plain object."); + throw new Error("not a plain object.") } if (Object.keys(obj).length === 0) { - throw new Error("object is empty."); + throw new Error("object is empty.") } - return obj; - }; + return obj + } - return abstractTransport(buildFn, { parseLine: parseLineFn }); + return abstractTransport(buildFn, { parseLine: parseLineFn }) } /** @@ -108,12 +107,12 @@ export function filterOptions( options: Partial, keys: (keyof T)[] ): Partial | undefined { - let result: Partial | undefined; + let result: Partial | undefined for (const key of keys) { if (key in options) { - result = result || {}; - result[key] = options[key]; + result = result || {} + result[key] = options[key] } } - return result; + return result } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 04024c7..682d362 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: husky: specifier: ^9.0.11 version: 9.0.11 + lint-staged: + specifier: ^15.2.7 + version: 15.2.7 rimraf: specifier: ^5.0.7 version: 5.0.7 @@ -165,6 +168,9 @@ importers: '@tanstack/react-query': specifier: ^5.40.1 version: 5.44.0(react@18.3.1) + '@tanstack/react-virtual': + specifier: ^3.5.1 + version: 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) chalk: specifier: ^5.3.0 version: 5.3.0 @@ -174,6 +180,9 @@ importers: clsx: specifier: ^2.1.1 version: 2.1.1 + date-fns: + specifier: ^3.6.0 + version: 3.6.0 fastify: specifier: ^4.27.0 version: 4.27.0 @@ -1337,6 +1346,15 @@ packages: peerDependencies: react: ^18.0.0 + '@tanstack/react-virtual@3.5.1': + resolution: {integrity: sha512-jIsuhfgy8GqA67PdWqg73ZB2LFE+HD9hjWL1L6ifEIZVyZVAKpYmgUG4WsKQ005aEyImJmbuimPiEvc57IY0Aw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + + '@tanstack/virtual-core@3.5.1': + resolution: {integrity: sha512-046+AUSiDru/V9pajE1du8WayvBKeCvJ2NmKPy/mR8/SbKKrqmSbj7LJBfXE+nSq4f5TBXvnCzu0kcYebI9WdQ==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -1563,6 +1581,10 @@ packages: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} + ansi-escapes@6.2.1: + resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==} + engines: {node: '>=14.16'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -1757,6 +1779,14 @@ packages: class-variance-authority@0.7.0: resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==} + cli-cursor@4.0.0: + resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + cli-truncate@4.0.0: + resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} + engines: {node: '>=18'} + cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} @@ -1792,6 +1822,10 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -1896,6 +1930,9 @@ packages: resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} engines: {node: '>= 0.4'} + date-fns@3.6.0: + resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} + dateformat@4.6.3: resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} @@ -1985,6 +2022,9 @@ packages: electron-to-chromium@1.4.798: resolution: {integrity: sha512-by9J2CiM9KPGj9qfp5U4FcPSbXJG7FNzqnYaY4WLzX+v2PHieVGmnsA4dxfpGE3QEC7JofpPZmn7Vn1B9NR2+Q==} + emoji-regex@10.3.0: + resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2067,6 +2107,9 @@ packages: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} @@ -2197,6 +2240,10 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-east-asian-width@1.2.0: + resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==} + engines: {node: '>=18'} + get-func-name@2.0.2: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} @@ -2419,6 +2466,14 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + + is-fullwidth-code-point@5.0.0: + resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==} + engines: {node: '>=18'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -2593,6 +2648,15 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + lint-staged@15.2.7: + resolution: {integrity: sha512-+FdVbbCZ+yoh7E/RosSdqKJyUM2OEjTciH0TFNkawKgvFp1zbGlEC39RADg+xKBG1R4mhoH2j85myBQZ5wR+lw==} + engines: {node: '>=18.12.0'} + hasBin: true + + listr2@8.2.3: + resolution: {integrity: sha512-Lllokma2mtoniUOS94CcOErHWAug5iu7HOmDrvWgpw8jyQH2fomgB+7lZS4HWZxytUuQwkGOwe49FvwVaA85Xw==} + engines: {node: '>=18.0.0'} + load-yaml-file@0.2.0: resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==} engines: {node: '>=6'} @@ -2640,6 +2704,10 @@ packages: lodash.upperfirst@4.3.1: resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==} + log-update@6.0.0: + resolution: {integrity: sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==} + engines: {node: '>=18'} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -2707,6 +2775,10 @@ packages: engines: {node: '>=10.0.0'} hasBin: true + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + mimic-fn@4.0.0: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} @@ -2807,6 +2879,10 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + onetime@6.0.0: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} @@ -2917,6 +2993,11 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} @@ -3152,6 +3233,10 @@ packages: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true + restore-cursor@4.0.0: + resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + ret@0.4.3: resolution: {integrity: sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==} engines: {node: '>=10'} @@ -3163,6 +3248,9 @@ packages: rfdc@1.3.1: resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==} + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rimraf@5.0.7: resolution: {integrity: sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==} engines: {node: '>=14.18'} @@ -3291,6 +3379,14 @@ packages: resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} engines: {node: '>=12'} + slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + + slice-ansi@7.1.0: + resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==} + engines: {node: '>=18'} + smartwrap@2.0.2: resolution: {integrity: sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==} engines: {node: '>=6'} @@ -3355,6 +3451,10 @@ packages: stream-transform@2.1.3: resolution: {integrity: sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==} + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -3363,6 +3463,10 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string-width@7.1.0: + resolution: {integrity: sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==} + engines: {node: '>=18'} + string.prototype.trim@1.2.9: resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} engines: {node: '>= 0.4'} @@ -3768,6 +3872,10 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} + wrap-ansi@9.0.0: + resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} + engines: {node: '>=18'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -5013,6 +5121,14 @@ snapshots: '@tanstack/query-core': 5.44.0 react: 18.3.1 + '@tanstack/react-virtual@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@tanstack/virtual-core': 3.5.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + + '@tanstack/virtual-core@3.5.1': {} + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.24.7 @@ -5292,6 +5408,8 @@ snapshots: ansi-colors@4.1.3: {} + ansi-escapes@6.2.1: {} + ansi-regex@5.0.1: {} ansi-regex@6.0.1: {} @@ -5497,6 +5615,15 @@ snapshots: dependencies: clsx: 2.0.0 + cli-cursor@4.0.0: + dependencies: + restore-cursor: 4.0.0 + + cli-truncate@4.0.0: + dependencies: + slice-ansi: 5.0.0 + string-width: 7.1.0 + cliui@6.0.0: dependencies: string-width: 4.2.3 @@ -5529,6 +5656,8 @@ snapshots: colorette@2.0.20: {} + commander@12.1.0: {} + commander@2.20.3: {} commander@4.1.1: {} @@ -5632,6 +5761,8 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.1 + date-fns@3.6.0: {} + dateformat@4.6.3: {} debug@4.3.5: @@ -5702,6 +5833,8 @@ snapshots: electron-to-chromium@1.4.798: {} + emoji-regex@10.3.0: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -5840,6 +5973,8 @@ snapshots: event-target-shim@5.0.1: {} + eventemitter3@5.0.1: {} + events@3.3.0: {} execa@8.0.1: @@ -6003,6 +6138,8 @@ snapshots: get-caller-file@2.0.5: {} + get-east-asian-width@1.2.0: {} + get-func-name@2.0.2: {} get-intrinsic@1.2.4: @@ -6210,6 +6347,12 @@ snapshots: is-fullwidth-code-point@3.0.0: {} + is-fullwidth-code-point@4.0.0: {} + + is-fullwidth-code-point@5.0.0: + dependencies: + get-east-asian-width: 1.2.0 + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -6359,6 +6502,30 @@ snapshots: lines-and-columns@1.2.4: {} + lint-staged@15.2.7: + dependencies: + chalk: 5.3.0 + commander: 12.1.0 + debug: 4.3.5 + execa: 8.0.1 + lilconfig: 3.1.2 + listr2: 8.2.3 + micromatch: 4.0.7 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.4.5 + transitivePeerDependencies: + - supports-color + + listr2@8.2.3: + dependencies: + cli-truncate: 4.0.0 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 6.0.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.0 + load-yaml-file@0.2.0: dependencies: graceful-fs: 4.2.11 @@ -6401,6 +6568,14 @@ snapshots: lodash.upperfirst@4.3.1: {} + log-update@6.0.0: + dependencies: + ansi-escapes: 6.2.1 + cli-cursor: 4.0.0 + slice-ansi: 7.1.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.0 + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -6471,6 +6646,8 @@ snapshots: mime@3.0.0: {} + mimic-fn@2.1.0: {} + mimic-fn@4.0.0: {} min-indent@1.0.1: {} @@ -6560,6 +6737,10 @@ snapshots: dependencies: wrappy: 1.0.2 + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + onetime@6.0.0: dependencies: mimic-fn: 4.0.0 @@ -6651,6 +6832,8 @@ snapshots: picomatch@2.3.1: {} + pidtree@0.6.0: {} + pify@2.3.0: {} pify@4.0.1: {} @@ -6899,12 +7082,19 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@4.0.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + ret@0.4.3: {} reusify@1.0.4: {} rfdc@1.3.1: {} + rfdc@1.4.1: {} + rimraf@5.0.7: dependencies: glob: 10.4.1 @@ -7041,6 +7231,16 @@ snapshots: slash@4.0.0: {} + slice-ansi@5.0.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + + slice-ansi@7.1.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 5.0.0 + smartwrap@2.0.2: dependencies: array.prototype.flat: 1.3.2 @@ -7104,6 +7304,8 @@ snapshots: dependencies: mixme: 0.5.10 + string-argv@0.3.2: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -7116,6 +7318,12 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + string-width@7.1.0: + dependencies: + emoji-regex: 10.3.0 + get-east-asian-width: 1.2.0 + strip-ansi: 7.1.0 + string.prototype.trim@1.2.9: dependencies: call-bind: 1.0.7 @@ -7580,6 +7788,12 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.1.0 + wrap-ansi@9.0.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 7.1.0 + strip-ansi: 7.1.0 + wrappy@1.0.2: {} y18n@4.0.3: {}